OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4205|回复: 8

【求教:关于W5500阻塞通信下,如何使用状态机的问题?】

[复制链接]

10

主题

37

帖子

0

精华

初级会员

Rank: 2

积分
113
金钱
113
注册时间
2014-1-20
在线时间
15 小时
发表于 2017-11-7 16:16:09 | 显示全部楼层 |阅读模式
4金钱
在使用STM32+W5500的socket编程时,根据例子,作为tcp客户端有如下的操作

[mw_shl_code=applescript,true]
        while(1)
        {
     //接收TCP服务器发送的数据
    ret = recv(SOCK_TCPS,gDATABUF,DATA_BUF_SIZE);

    if(ret <= 0){
     //continue;
     }else{
    //将接收的数据原样返回给TCP服务器
    ret = send(SOCK_TCPS,gDATABUF,ret);
     }
        }
[/mw_shl_code]

但追踪 recv(SOCK_TCPS,gDATABUF,DATA_BUF_SIZE);这个函数发现,它是一个阻塞式的通信。程序会一直在recv()中循环,直到接收到服务器的数据。
但我还要其他的操作需要去执行,如果将要执行的其他操作放在中断中,有不是很合理。希望以状态机的方式来处理不同的事件。

所以向大家请请教一下,这个怎么处理?


最佳答案

查看完整内容[请看2#楼]

自己解决了。 由于默认使用了阻塞的socket,所以一直在等待数据返回。只要在于服务器建立了连接后,使用ctlsocket函数,将连接设置为非阻塞的就可以了。 ret = ctlsocket(SOCK_TCPS,CS_SET_IOMODE,&NONBLOCK); NONBLOCK这个是自己写的一个变量,按手册应该写的是SOCK_IO_NONBLOCK,但SOCK_IO_NONBLOCK是#define 定义的,使用Keil编译不通过,所以自己写了一个变量代替。 还有就是使用了非阻塞的模式之后recv函数有了变化 / ...
“你要保守你的心,胜过保守一切,因为一生的果效,都是由心发出”
("Above?all?else,guard?your?heart,for?it?is?the?wellspring?of?life"---NIV)。
哭着喊着也要进步。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

10

主题

37

帖子

0

精华

初级会员

Rank: 2

积分
113
金钱
113
注册时间
2014-1-20
在线时间
15 小时
 楼主| 发表于 2017-11-7 16:16:10 | 显示全部楼层
自己解决了。
由于默认使用了阻塞的socket,所以一直在等待数据返回。只要在于服务器建立了连接后,使用ctlsocket函数,将连接设置为非阻塞的就可以了。
ret = ctlsocket(SOCK_TCPS,CS_SET_IOMODE,&NONBLOCK);
NONBLOCK这个是自己写的一个变量,按手册应该写的是SOCK_IO_NONBLOCK,但SOCK_IO_NONBLOCK是#define 定义的,使用Keil编译不通过,所以自己写了一个变量代替。

还有就是使用了非阻塞的模式之后recv函数有了变化
/在阻塞状态,无数据时,阻塞
//返回大于0的数值表示接受到的数据
//返回小于0的数值表示错误

/在非阻塞状态下,无数据返回的是SOCK_BUSY,即0
//小于0时,表示错误
//大于0时,表示接收数据长度


因此需要修改对recv函数返回值的判断条件

截取了函数片段
[mw_shl_code=c,true]// TODO 新建套接字
    ret = socket(SOCK_TCPS,Sn_MR_TCP,5000,0x00);
        if(ret != SOCK_TCPS){
                printf("%d:Socket Error\r\n",SOCK_TCPS);
                while(1);
        }else{
                printf("%d:Socket Opened\r\n",SOCK_TCPS);
        }

      
  
   

    //连接TCP服务器
        ret = connect(SOCK_TCPS,DstIP,DstPort);
        if(ret != SOCK_OK){
                printf("%d:Socket Connect Error  ret = %d \r\n",SOCK_TCPS,ret);
                while(1);
        }

    printf("Socket Connect Server IP %d.%d.%d.%d  Port %d OK \r\n",DstIP[0],DstIP[1],DstIP[2],DstIP[3],DstPort);
  

    //设置为非阻塞
   ret = ctlsocket(SOCK_TCPS,CS_SET_IOMODE,&NONBLOCK);
   if(ret != SOCK_OK){
       printf(" ctlsocket SOCK_IO_NONBLOCK error \r\n");
       while(1);
   }else{
      printf(" ctlsocket SOCK_IO_NONBLOCK ok \r\n");
   }
   
    //开启定时器
    timer_Start();  
   
        while(1)
        {
                //接收TCP服务器发送的数据
                //在阻塞状态,无数据时,阻塞
                //返回大于0的数值表示接受到的数据

        //在非阻塞状态下,无数据返回的是SOCK_BUSY,即0
        //小于0时,表示错误
        //大于0时,表示接收数据长度
                fd = recv(SOCK_TCPS,gDATABUF,DATA_BUF_SIZE);
                if(fd == SOCK_BUSY){
                        //continue;
                        //没有数据
                }else if(fd < 0){
            //  TODO 接受错误
        }else{
            //将接收的数据原样返回给TCP服务器
           
                    fd = send(SOCK_TCPS,gDATABUF,fd);
        }
}[/mw_shl_code]
“你要保守你的心,胜过保守一切,因为一生的果效,都是由心发出”
("Above?all?else,guard?your?heart,for?it?is?the?wellspring?of?life"---NIV)。
哭着喊着也要进步。
回复

使用道具 举报

0

主题

51

帖子

0

精华

高级会员

Rank: 4

积分
654
金钱
654
注册时间
2016-12-14
在线时间
332 小时
发表于 2017-11-7 16:56:29 | 显示全部楼层
先读w5500的接收长度大于0再收数据
回复

使用道具 举报

10

主题

37

帖子

0

精华

初级会员

Rank: 2

积分
113
金钱
113
注册时间
2014-1-20
在线时间
15 小时
 楼主| 发表于 2017-11-7 17:22:55 | 显示全部楼层
szjx1212 发表于 2017-11-7 16:56
先读w5500的接收长度大于0再收数据

[mw_shl_code=c,true]int32_t recv(uint8_t sn, uint8_t * buf, uint16_t len)
{
   uint8_t  tmp = 0;
   uint16_t recvsize = 0;
   CHECK_SOCKNUM();
   CHECK_SOCKMODE(Sn_MR_TCP);
   CHECK_SOCKDATA();
   
   recvsize = getSn_RxMAX(sn);
   if(recvsize < len) len = recvsize;
   while(1)
   {
      recvsize = getSn_RX_RSR(sn);
      tmp = getSn_SR(sn);
      if (tmp != SOCK_ESTABLISHED)
      {
         if(tmp == SOCK_CLOSE_WAIT)
         {
            if(recvsize != 0) break;
            else if(getSn_TX_FSR(sn) == getSn_TxMAX(sn))
            {
               close(sn);
               return SOCKERR_SOCKSTATUS;
            }
         }
         else
         {
            close(sn);
            return SOCKERR_SOCKSTATUS;
         }
      }
      if((sock_io_mode & (1<<sn)) && (recvsize == 0)) return SOCK_BUSY;
      if(recvsize != 0) break;
   }
   if(recvsize < len) len = recvsize;
   wiz_recv_data(sn, buf, len);
   setSn_CR(sn,Sn_CR_RECV);
   while(getSn_CR(sn));
   return len;
}
[/mw_shl_code]


这是recv的源码,  它可以说是一个阻塞的tcp通信,在未收到数据或是发生错误时候,程序一直在他内部运行,所以它是阻塞的,在未收到数据或是发生错误时候,recv是不返回任何数据的。


难道要加一个超时接受的处理?
“你要保守你的心,胜过保守一切,因为一生的果效,都是由心发出”
("Above?all?else,guard?your?heart,for?it?is?the?wellspring?of?life"---NIV)。
哭着喊着也要进步。
回复

使用道具 举报

0

主题

51

帖子

0

精华

高级会员

Rank: 4

积分
654
金钱
654
注册时间
2016-12-14
在线时间
332 小时
发表于 2017-11-7 18:32:24 | 显示全部楼层
if(getSn_RX_RSR(SOCK_TCPS)>0)
{

    ret = recv(SOCK_TCPS,gDATABUF,DATA_BUF_SIZE);

}
回复

使用道具 举报

10

主题

37

帖子

0

精华

初级会员

Rank: 2

积分
113
金钱
113
注册时间
2014-1-20
在线时间
15 小时
 楼主| 发表于 2017-11-7 20:58:41 | 显示全部楼层
szjx1212 发表于 2017-11-7 18:32
if(getSn_RX_RSR(SOCK_TCPS)>0)
{

没看明白,我是使用socket编程的,你说的我在研究一下吧。
“你要保守你的心,胜过保守一切,因为一生的果效,都是由心发出”
("Above?all?else,guard?your?heart,for?it?is?the?wellspring?of?life"---NIV)。
哭着喊着也要进步。
回复

使用道具 举报

4

主题

346

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3657
金钱
3657
注册时间
2016-2-21
在线时间
542 小时
发表于 2017-11-8 09:17:51 | 显示全部楼层
标准的socket就是要阻塞的,才符合顺序流程的架构
回复

使用道具 举报

0

主题

9

帖子

0

精华

高级会员

Rank: 4

积分
577
金钱
577
注册时间
2015-11-5
在线时间
47 小时
发表于 2017-11-8 09:39:00 | 显示全部楼层
我记得上海本宏电子有相关FAE支持,但是前提是得用他们家的芯片
回复

使用道具 举报

8

主题

82

帖子

0

精华

初级会员

Rank: 2

积分
178
金钱
178
注册时间
2017-5-23
在线时间
17 小时
发表于 2018-1-3 14:06:02 | 显示全部楼层
yettt365 发表于 2017-11-7 20:59
自己解决了。
由于默认使用了阻塞的socket,所以一直在等待数据返回。只要在于服务器建立了连接后,使用ct ...

楼主厉害,楼主是在深圳吗,如果是的话,可以一起来交流一下,我们每个月都会举办一次。

W5500代理商深圳炜世科技与WIZnet,在深圳携手举办“物联网通信协议详解与实践活动”公开课,司为广大学习嵌入式以太网技术提供的一个互动交流的平台。由WIZnet资深工程师陈海峰博士亲自授课,机会难得,报名方式【姓名+公司名称+手机号+QQ】发送到邮箱support@wisioe.com,邮件收到后将会电话或者邮件形式通知。

技术支持 0755-86568556
WIZnet 以太网芯片 w5500 Dai Li 商 深圳炜世科技0755-86568556  QQ2574989918
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-7-23 03:49

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表