client connect问题

2019-03-24 16:18发布

本人在做LM3S8962作为客户端测试时,遇到个问题,如果TCP测试软件建立服务器后,客户端有可能会等很久才连上来,关掉了这个连接,就再也建立不上与8962的通信。迷惑中,请高手帮帮忙,万分感谢!我的源码如下:                                //-----------------------------------------------------------------------------
//
// enet_lwip_tcp.c - 一个简单的lwIP tcp通信例程
//
//----------------------------------------------------------------------------- #include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_nvic.h"
#include "inc/hw_types.h"
#include "driverlib/ethernet.h"
#include "driverlib/flash.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "utils/lwiplib.h"
#include "utils/uartstdio.h"
#include "utils/truly128x64.h"
#include "utils/ustdlib.h"
#include <LM3Sxxxx.h> //----------------------------------------------------------------------------
//! 这个例子展示了对Stellaris以太网控制器的使用,通过lwIP TCP/IP 协议栈
//  http://savannah.nongnu.org/projects/lwip/
//----------------------------------------------------------------------------
#define ulPORT  3000 //----------------------------------------------------------------------------
//
// Defines for setting up the system clock.
// 定义systick时钟
//-----------------------------------------------------------------------------
#define SYSTICKHZ               100
#define SYSTICKMS               (1000 / SYSTICKHZ) unsigned char sent_ok_flag = 0;
struct tcp_pcb *now_pcb;
char tmpbuf[20];
void *ptr;
struct ip_addr ipaddr; //-----------------------------------------------------------------------------
//
// 显示lwip的IP地址信息函数
//
//-----------------------------------------------------------------------------
void
DisplayIPAddress(unsigned long ipaddr, unsigned long ulCol,
                 unsigned long ulRow)
{
    char pucBuf[16];
    unsigned char *pucTemp = (unsigned char *)&ipaddr;     //
    // 转换IP地址到字符串
    //
    usprintf(pucBuf, "%d.%d.%d.%d", pucTemp[0], pucTemp[1], pucTemp[2],
             pucTemp[3]);     //
    //显示字符串
    //
    Oled_Dis_string(ulCol,ulRow,pucBuf);
}
//-----------------------------------------------------------------------------
//
// 被lwIp库使用,用来支持任何主机相关的定时功能
//
//-----------------------------------------------------------------------------
void
lwIPHostTimerHandler(void)
{
    static unsigned long ulLastIPAddress = 0;
    unsigned long ulIPAddress;
    char pucBuf[16];     ulIPAddress = lwIPLocalIPAddrGet();     //
    // If IP Address has not yet been assigned, update the display accordingly
    //
    if(ulIPAddress == 0)
    {     }
    //
    // Check if IP address has changed, and display if it has.
    //
    else if(ulLastIPAddress != ulIPAddress)
    {       
  ulLastIPAddress = ulIPAddress;
  Oled_Dis_string(2,2,"IP:   ");
  Oled_Dis_string(3,2,"MASK: ");
  Oled_Dis_string(4,2,"GW:   ");
  Oled_Dis_string(5,2,"Port: ");
        DisplayIPAddress(ulIPAddress, 2, 38);
        ulIPAddress = lwIPLocalNetMaskGet();
        DisplayIPAddress(ulIPAddress, 3, 38);
        ulIPAddress = lwIPLocalGWAddrGet();
        DisplayIPAddress(ulIPAddress, 4, 38);
  usprintf(pucBuf, "%d", ulPORT);
  Oled_Dis_string(5, 38,pucBuf);
    }
}
//-----------------------------------------------------------------------------
//
// systick中断处理函数
//
//-----------------------------------------------------------------------------
void
SysTickIntHandler(void)
{
    //
    // 调用lwip定时处理函数
    //
    lwIPTimer(SYSTICKMS);
}
//-----------------------------------------------------------------------------
//
// 发送完成回调函数
//
//-----------------------------------------------------------------------------
err_t Sent_Ok(void *arg,struct tcp_pcb *pcb,u16_t err)
{
   tcp_close(pcb);
   return ERR_OK;
}
//-----------------------------------------------------------------------------
//
// 接收到数据的回调函数
//
//-----------------------------------------------------------------------------
err_t recv_now(void *arg,struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
     if(p != NULL)                              //如果收到的数据不为空              
   {
    
   tcp_write(tpcb,p->payload,p->len,0);     //将接收到的数据发送出去        
     pbuf_free(p);                            // 释放缓冲区数据
  tcp_recved(tpcb,p->tot_len);
  //tcp_output(tpcb);
   
   }
   return ERR_OK; 
} //-----------------------------------------------------------------------------
//
// 接受连接请求
//
//-----------------------------------------------------------------------------
err_t TCP_SER_Connected(void *arg, struct tcp_pcb *pcb, err_t err)
  {
 
  //
     // Clear out all of the TCP callbacks.
     //
     tcp_arg(pcb, NULL);
     tcp_sent(pcb, NULL);
     tcp_recv(pcb, NULL);
     tcp_err(pcb, NULL);
     tcp_poll(pcb, NULL, 1);      //
     // Close the TCP connection.
     //
    tcp_close(pcb);
   tcp_recv(pcb,recv_now);
 
 return(ERR_OK);
} /*****************************************************************************************
** Function name:       TCP_SER_Poll
** Descriptions:        接收处理函数
** input parameters:    无
** output parameters:   无
** Returned value:      无
*****************************************************************************************/
 err_t TCP_SER_Poll(void *arg, struct tcp_pcb *pcb)
 {
    err_t eError;
 eError = tcp_connect(pcb, &ipaddr, ulPORT, TCP_SER_Connected);  if(eError != ERR_OK)
    {
       
        return 1;
    }
     return 0;
  }
/*****************************************************************************************
** Function name:       TCP_Client_Init
** Descriptions:        客户端模式初始化网络连接
** input parameters:    ulIPAddr
** output parameters:   无
** Returned value:      无
*****************************************************************************************/ 
 void TCP_Client_Init(unsigned long ulIPAddr)
  {
 struct tcp_pcb *local_pcb;
      err_t eError;
 ipaddr.addr = htonl(ulIPAddr);     local_pcb = tcp_new();                      
  tcp_poll(local_pcb, TCP_SER_Poll, (3000 / TCP_SLOW_INTERVAL));
   eError = tcp_connect(local_pcb, &ipaddr, ulPORT, TCP_SER_Connected);
 if(eError != ERR_OK)
    {
       
        return;
    }
   
   }  
//-----------------------------------------------------------------------------
//
// 使用以太网控制器的一个例子
//
//-----------------------------------------------------------------------------
int
main(void)
{
    unsigned long ulUser0 = 0x12345678, ulUser1 = 0x12345678 ;
    unsigned char pucMACArray[8];
    unsigned long ulIPAddr,ulIPMask,ulIPGateWay,ulIPAddrR;
    //
    //设定系统时钟8MHZ
    //
    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
                       SYSCTL_XTAL_8MHZ);     //
    // 初始化 OLED 显示.
    //
    Oled_Init();
    Oled_Dis_string(1,10,"Enet lwip Tcp Test");
      //
    // 使能以太网控制器,然后复位以太网控制器
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ETH);
    SysCtlPeripheralReset(SYSCTL_PERIPH_ETH);
 SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);     //
    // 使能端口F来作为以太网的LED使用
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    GPIOPinConfigure(GPIO_PF2_LED1);
    GPIOPinConfigure(GPIO_PF3_LED0);
    GPIOPinTypeEthernetLED(GPIO_PORTF_BASE, GPIO_PIN_2 | GPIO_PIN_3);
 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);                 //使能Uart时钟 
    GPIOPinTypeUART(GPIO_PORTA_BASE,GPIO_PIN_0 | GPIO_PIN_1);    //配置引脚为Rx、Tx功能 
 
 //
 //配置UART0
 //
 UARTConfigSetExpClk(UART0_BASE,SysCtlClockGet(),9600,
    UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE);
                                                               //配置为9600,8位,1个停止位,无校验
   UARTIntEnable(UART0_BASE,UART_INT_RT | UART_INT_RX);         //使能接收中断和接受超时中断
   UARTEnable(UART0_BASE);                                      //启动Uart
 
   IntEnable(INT_UART0);                                        //使能Uart中断     //
    // 配置systick
    //
    SysTickPeriodSet(SysCtlClockGet() / SYSTICKHZ);
    SysTickEnable();
    SysTickIntEnable();     //
    //使能处理器中断
    //
    IntMasterEnable();     //
    //从用户寄存器中 读取MAC地址
    //
    //ROM_FlashUserGet(&ulUser0, &ulUser1);
    if((ulUser0 == 0xffffffff) || (ulUser1 == 0xffffffff))
    {
        //
        // MAC没有编程
        //
        Oled_Dis_string(5,5,"MAC Not Programmed!");
        while(1)
        {
        }
    }     //
    //转换用户寄存器到MAC地址
    //
    pucMACArray[0] = ((ulUser0 >>  0) & 0xff);
    pucMACArray[1] = ((ulUser0 >>  8) & 0xff);
    pucMACArray[2] = ((ulUser0 >> 16) & 0xff);
    pucMACArray[3] = ((ulUser1 >>  0) & 0xff);
    pucMACArray[4] = ((ulUser1 >>  8) & 0xff);
    pucMACArray[5] = ((ulUser1 >> 16) & 0xff);     //
    // 初始化lwIP协议栈  静态IP
 // IP地址:   192.168.14.20
    // 子网掩码:255.255.255.0
 // 默认网关:192.168.14.254
    ulIPAddr = (((unsigned long )192<<24)|(168<<16)|(2<<8)|20);
 ulIPMask = ((unsigned long )255<<24)|(255<<16)|(255<<8)|0;
 ulIPGateWay = ((unsigned long )192<<24)|(168<<16)|(2<<8)|254;
 ulIPAddrR = (((unsigned long )192<<24)|(168<<16)|(2<<8)|6);
    lwIPInit(pucMACArray, ulIPAddr,
                       ulIPMask,
        ulIPGateWay, IPADDR_USE_STATIC);  //
 //初始化客户端TCP
 //
 TCP_Client_Init(ulIPAddrR);     //
    // 主循环
    //
    while(1)
    {
    }
}
此帖出自小平头技术问答
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
17条回答
ebuffalo
1楼-- · 2019-03-25 12:25
上面是风版主发的一个帖子,上面帖子中的问题解决了么?
qwertyer2010
2楼-- · 2019-03-25 18:15
 精彩回答 2  元偷偷看……
历史的天空
3楼-- · 2019-03-25 23:02
问题出在这句函数调用: tcp_close(pcb);  // 这句话是你关闭了连接,所以下次通信就要重新连接!


历史的天空
4楼-- · 2019-03-26 01:53

原帖由 ebuffalo 于 2011-3-15 17:13 发表 据说LWIP无法用来做客户端。

 

纯属胡说!!

ebuffalo
5楼-- · 2019-03-26 02:54
 精彩回答 2  元偷偷看……
ebuffalo
6楼-- · 2019-03-26 05:20
搞死LWIP的方法
RT-Thread核心开发、使用讨论

版主: bernard  

发表回复4 篇帖子 • 分页: 1 / 1  
搞死LWIP的方法
由 mbbill &raquo; 2010年 4月 18日 03:29  

lwip的netconn有一个缺陷,它的tcp window和输入缓冲区没有直接联系,输入的数据是以pbuf的形式存放在conn->recvmbox里面的,这个mbox尺寸是10,这个size和缓冲区的大小无关,只是数据包的数量。
现在假设TCP_WND是1024,网络端快速发过来几十个1字节的数据包,这时候上面的mbox就会很快溢出,溢出的第一个包在pcb->refused_data里面会缓存一下,不过这个能力也很有限,等pcb->refused_data也存不下了这个pbuf就被直接丢弃了。这是在TCP_WND还没用完的情况下就丢包了。
更严重一点的情况,如果上面这种状况发生的同时lwip还在向上位机程序发数据的话,之前被丢弃的包很可能同时也是这些数据包的ACK,ACK丢了就会导致lwip向上位机重发这些数据,而上位机这边也在不停的重发(window没用完却丢包了必然会重发),然后两边就互不理睬各发各的。。。最后rst。断开。

这种情况有两个前提,一个是接受速度没那么快,这种情况我觉得还是比较容易发生的,比如一边收网络包一边发送到usart,波特率慢的时候网络接收就会很慢。
还有一个前提是上位机发来大量段数据包,且这些数据包总和x10 < TCP_WND。

目前还没想到很好的办法解决这个问题,加大mbox或者减小window只能稍微缓解一下,只要mbox的size<TCP_WND这个问题都会存在。个人觉得。。。这个问题有点严重,大家帮忙出出主意吧mbbill  
   
帖子: 33
注册: 2009年 12月 20日 03:35 页首
--------------------------------------------------------------------------------
Re: 搞死LWIP的方法
由 bernard &raquo; 2010年 4月 18日 07:23  

嗯,这个确实是个大问题。

修正下才是,mbox机制需要修改下,改成非mbox机制比较好。
我的邮件地址:
和RT-Thread相关的基础技术问题请在论坛上直接发帖,就不要发信给我啦,谢谢。bernard  
   
帖子: 1362
注册: 2008年 5月 10日 07:22 页首
--------------------------------------------------------------------------------
Re: 搞死LWIP的方法
由 mbbill &raquo; 2010年 4月 18日 14:51  

这样工作量有点大了   

另外这个问题在优化lwip的时候也很可能发生,比如为了提高性能把TCP_BUF和TCP_WND定的比较大,这时候很可能就会发生这种现象,wireshark一抓全都是重发的包。mbbill  
   
帖子: 33
注册: 2009年 12月 20日 03:35 页首
--------------------------------------------------------------------------------
Re: 搞死LWIP的方法
由 bernard &raquo; 2010年 4月 18日 16:14  

工作量可能还行,可以考虑把mbox更改成数据队列的方式。只是这样的话,那么lwip那边tcp线程确实会修改一些了。这个加上,系能是否会好些呢。

找个时间验证一把。

一周热门 更多>

相关问题

    相关文章