[求助] LwIP 的TCP连接无法同时收发问题请教。

warcraftiii   2011-11-9 11:38 楼主
结构:LMS8962的板子跟PC连接,TCP协议,无操作系统。PC端程序是VC写的,测试都正常。
功能:板子向PC发送3个 unsigned int,PC向板子发送1个unsigned int
现象:单独写了板子向PC发送程序:板子正常发送,PC端正常接收到。
      单独写了板子接收PC发送字符的程序:板子正常接收,PC端正常发送。

问题:两个程序的功能合在一起后,必须板子先启动,然后运行PC程序,板子才能接收到数据。但板子始终无法发送数据,连自定义的发送回调函数都进不去。

下面是初始化代码。各位给指点下,这么写有问题没?

#define TCP_PORT_PMSM60 4000    // TCP port : 4000
void tcpclient_init()
{
  struct tcp_pcb *pcb;
  UARTprintf("tcpclient_init\n");
  IP4_ADDR(&ipaddr, 119,78,208,24);  //Server PC IP address
  pcb = tcp_new();
  tcp_bind(pcb, IP_ADDR_ANY, TCP_PORT_PMSM60);
  pcb = tcp_listen(pcb);
  tcp_accept(pcb, tcp_acceptset);
  tcp_connect(pcb, &ipaddr, TCP_PORT_PMSM60, tcp_connected);
}

向看帖的筒子致敬!!!!!

回复评论 (27)

回复 楼主 warcraftiii 的帖子

都是 板子作为 Server 吗?
点赞  2011-11-9 20:20
PC做Server, 板子做Client。 板子向PC发3个无符号整形数据,接收PC发过来的1个无符号整形数据。就这点功能。改了一下tcpclient_init()
=========================================================
void tcpclient_init()
{
  struct tcp_pcb *pcb;
  struct ip_addr ipaddr;
   struct tcp_pcb *pcb_send;
  
  UARTprintf("tcpclient_init\n");
  IP4_ADDR(&ipaddr, 119,78,208,24);  //Server PC IP address
  pcb = tcp_new();
  tcp_bind(pcb, IP_ADDR_ANY, TCP_PORT_PMSM60);
  pcb = tcp_listen(pcb);
  tcp_accept(pcb, tcp_acceptset);

  pcb_send = tcp_new();
  tcp_bind(pcb_send, IP_ADDR_ANY, TCP_PORT_PMSM60);
  tcp_connect(pcb_send, &ipaddr, TCP_PORT_PMSM60, tcp_connected);
}
这回板子发送数据后,PC程序出现Debug Assertion Failed!错误。忽略后能显示收到的数据。但是板子收不到PC发来的数据。
点赞  2011-11-9 21:48
板子初始化:
pcb = tpc_new();                //接收pcb
pcb_send = tpc_new();    //发送pcb
tcp_bind(pcb, IP_ADDR_ANY, TCP_PORT_PMSM60);
tcp_bind(pcb_send, IP_ADDR_ANY, TCP_PORT_PMSM60);
收发使用两个pcb,与同一个端口绑定,是否可以这样设置?

PC端使用CAsyncSocket类定义了两个socket:       
m_sListenSocket;     //监听
m_sConnectSocket; //发送
PC程序与PC程序间收发数据都正常(这两个PC程序类似),但是PC向板子发送数据(下面这句)
m_sConnectSocket.Send(LPCTSTR(m_strSpeed), iLen)
出现错误,错误代码10038:WSAENOTSOCK   

对LwIP的TCP收发流程不理解,迷糊呀!
点赞  2011-11-10 16:29
设定板子向PC发送10遍数据, 但实际只发了7遍
点赞  2011-11-10 16:43
PC的Server
接收连接:m_sListenSocket.Accept(m_sConnectSocket);
接收数据:m_sConnectSocket.Receive(pBuf, iBufSize);
发送数据:m_sConnectSocket.Send(LPCTSTR(m_strSpeed), iLen);
Server程序并没有明确设定客户端IP和端口的语句,至少我没写,但是却能向另一个PC上的Client程序发送数据。

MFC的Socket程序接收和发送用的是同一个端口么?
LwIP的接收和发送用的是同一个端口么?

尽情的鄙视我吧,鄙视完了给讲讲哈!
点赞  2011-11-10 16:58
要看回调函数里的,你可以参考下周立功的呀。你用的TCP还是UDP的。做过UDP的成了,UDP的简单点。

[ 本帖最后由 o0pingu0o 于 2011-11-10 17:11 编辑 ]
点赞  2011-11-10 17:09
引用: 原帖由 warcraftiii 于 2011-11-9 11:38 发表
结构:LMS8962的板子跟PC连接,TCP协议,无操作系统。PC端程序是VC写的,测试都正常。
功能:板子向PC发送3个 unsigned int,PC向板子发送1个unsigned int
现象:单独写了板子向PC发送程序:板子正常发送,PC端正常 ...

PC 作为 Server,板子就是客户端啊。
那怎么还有这样的呢?
pcb = tcp_listen(pcb);
tcp_accept(pcb, tcp_acceptset);
点赞  2011-11-10 19:51
感谢二位回复!

是想让板子做客户端。
板子发送是参考周立功“LwIP的RAW API接口及编程指南”的例子。
板子接收是参考斑竹帖子“以太网学习的一点心得”和TI的httpd的HTTP接收代码。
单独调试基本上都可以了,放在一起就不行。

回o0pingu0o
考虑到以后要用到长时间连接和数据刷新,选择了TCP。也正好PC上有个VC的TCP例子,呵呵!
周立功的代码我只有上面那个,其他哪里能找到?

回 Study_Stellaris:
pcb = tcp_listen(pcb);
tcp_accept(pcb, tcp_acceptset);
这两句是为了接收。如果板子做Client,接收数据的初始化代码该怎么写呢?
我理解tcp_listen(pcb)是把pcb放到监听队列里。
tcp_accept(pcb, tcp_acceptset)是为了在tcp_input()里调用“tcp_acceptset”这个回调函数。
至于这两句间的关系,从代码上没看懂。
发送和接收在一起的初始化流程该怎么写呢?
点赞  2011-11-11 08:59

回复 8楼 Study_Stellaris 的帖子

板子作为客户端时,lwip TCP一般是这样的模式:
pcb = tcp_new();
tcp_bind(pcb,IP_ADDR_ANY,port);
tcp_poll(pcb,connectPoll,5);
tcp_connect(pcb,&IPAddr,port,callConnect);
端口的话要保证发送端口是你要发送的目标端口就行了!
点赞  2011-11-11 09:24

回复 9楼 warcraftiii 的帖子

我目前知道的是
pcb = tcp_listen(pcb);
tcp_accept(pcb, tcp_acceptset);
只在作为 TCP Server 的时候才调用。
作为客户端,按照楼上的就可以了。
点赞  2011-11-11 10:13
tcp_connect(pcb,&IPAddr,port,callConnect);里处理的是板子发送设置。
这个时候该怎么设置接收回调函数呢?
我改成下面的初始化设置,但还是不行,能发送,不能接收。
IP4_ADDR(&ipaddr, 119,78,208,24);  //Server PC IP address
pcb_send = tcp_new();
tcp_bind(pcb_send, IP_ADDR_ANY, 4000);
tcp_accept(pcb_send, tcp_acceptset);
tcp_connect(pcb_send, &ipaddr, 4000, tcp_connected);
点赞  2011-11-11 16:51
打开TCP_INPUT_DEBUT调试宏,发现板子实际已经接收到数据,而且接收的字节数与PC发送的字节数相等。
但是无法进入接收回调函数。接收TCP数据包如下:

tcp_input()
{......
TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);
......}

#define TCP_EVENT_RECV(pcb,p,err,ret)                           \
  do {                                                          \
    if((pcb)->recv != NULL) {                                   \
      (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); \
    } else {
      //进入到这里,(pcb->recv == NULL)                         \
      (ret) = tcp_recv_null(NULL, (pcb), (p), (err));           \
    }                                                           \
  } while (0)

debug结果是进入到tcp_recv_null(NULL, (pcb), (p), (err));
也就是说pcb->recv并没有指向回调函数。

调了一天,哇哇大哭呀!!!
点赞  2011-11-11 16:52
tcp_accept(pcb_send, tcp_acceptset);
tcp_connect(pcb_send, &ipaddr, 4000, tcp_connected);

我把回调函数tcp_acceptset、 tcp_connected
里面的tcp_close(pcb);删掉了,这个pcb还要用呢,为什么要close呢?
点赞  2011-11-11 17:00
接收数据时进入tcp_recv_null是因为之前TCP_EVENT_ACCEPT(pcb, ERR_OK, err);没有被执行。
此时pcb->state == ESTABLISHED
只有当pcb->state == SYN_RCVD的时候才能有机会执行TCP_EVENT_ACCEPT 。
tcp的发送和接受是否使用同一个pcb?
还是发送和接受各需要一个pcb?
pcb与端口是一一对应,还是可以一对多,多对一?

谢谢楼上的
求关注!!!
点赞  2011-11-14 17:24
求关注!!!
点赞  2011-11-15 17:21
在关注,我最近也在学习这个方面,很多问题都搞不明白。
比如:
关于 如何在lwIP中绑定一个确定的IP地址呢??
用netconn_bind是否能实现?
我看了lwIP中相关API资料,始终搞不定,特来请教,多谢了!!!
有目的的学习是最有效的学习!
点赞  2011-11-16 09:10
我目前用的例程就是论坛里面分享的一个uCOSii + lwIP 的WEB例子 ,请教了!
有目的的学习是最有效的学习!
点赞  2011-11-16 09:13
netconn_bind()是Sequential AP么?

现在只是在模仿例子程序,能看明白的只是回调函数一小块。
至于TCP从连接建立到关闭的过程,tpc_pcb在各种状态下的含义和处理方法等等,这些应该是TCP处理流程的主体。
用LwIP的代码来讲解这一流程的资料较少。
点赞  2011-11-16 10:31
TI 的http 例程使用的是RAW API,做服务器监听的绑定方式如下,不知道是否可以参考。
struct tcp_pcb *pcb;
  pcb = tcp_new();
  tcp_bind(pcb, IP_ADDR_ANY, 80);   
pcb = tcp_listen(pcb);
  tcp_accept(pcb, http_accept);
点赞  2011-11-16 11:37
12下一页
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复