搜索
bottom↓
回复: 6

rt-thread Lwip TCP 连接问题

[复制链接]

出0入0汤圆

发表于 2010-12-14 21:55:57 | 显示全部楼层 |阅读模式
我在做一个项目,类似网络终端和PC机连接,采用TCP方式,PC机做server,STM32F107+DP83848作为client,用RMII连接方式,协议采用RT-Thread+LwIP,现在ping的通,但连接有些问题,想请教一下各位高手,这个连接是要一直保持的,即使断开了,client端也要再次连接,编写了一个独立的TCP处理程序,如下
void rt_tcp_thread_entry(void* parameter)
{
        int socket_handle;
        int peer_handle;
        struct sockaddr_in server_addr;
        uint16_t port;
        W_B *TempW_B;
        int data_len;

        while(1)
        {
            while(1)
            {
                   rt_thread_delay(RT_TICK_PER_SECOND);
                // 创建一个socket,类型是SOCKET_STREAM,TCP类型
                if ((socket_handle = socket(AF_INET, SOCK_STREAM, 0))==-1)
                {
                  #if(BSP_DEBUG>0)
                     //创建socket失败
                     rt_kprintf("Socket error\n");
                   #endif
                   continue;
                 }
       
                //初始化预连接的服务端地址
                server_addr.sin_family = AF_INET;
       
                   port=Flash_Sys_Buf[FLASH_TCP_PORT+1]<<8;
                port+=Flash_Sys_Buf[FLASH_TCP_PORT];//8084端口
                server_addr.sin_port = htons(port);
       
                TempW_B=(W_B *)&Flash_Sys_Buf[FLASH_TCP_SERVER_IP];//192.168.0.103
                server_addr.sin_addr.s_addr= TempW_B->dword;
       
                rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
                       
                rt_thread_delay(RT_TICK_PER_SECOND);
                peer_handle = connect(socket_handle, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));//连接到服务端
                if (peer_handle ==0)//连接成功
                {
                    #if(BSP_DEBUG>0)
                        rt_kprintf("Socket connect ok\n");//创建socket成功
                    #endif
                      //Funcation_SystemStart_Send();//发送开机上报消息
                   break;
                }
                rt_thread_delay(RT_TICK_PER_SECOND*5);
                #if(BSP_DEBUG>0)
                    rt_kprintf( "Socket=%d connect fail\n", socket_handle );
                #endif
                peer_handle=closesocket(socket_handle);
                if(peer_handle<0)
                {
                    #if(BSP_DEBUG>0)
                        rt_kprintf( "Socket=%d close fail\n", socket_handle );
                       #endif
                       rt_thread_delay(RT_TICK_PER_SECOND*10);
                }
        }
        while(1)
        {
             //从sock连接中接收最大1024字节数据
            data_len = recv(socket_handle, Eth_Buf, sizeof(Eth_Buf), 0);
              if (data_len < 0)//连接错误
           {
               #if(BSP_DEBUG>0)
                 //socket失败
                 rt_kprintf("Socket rec error\n");
              #endif
             lwip_close(socket_handle);
                rt_thread_delay(RT_TICK_PER_SECOND);
            break;
          }
        if(data_len)//有有效数据
           {
             Eth_Buf[data_len]=0;
             rt_kprintf("tcp rec:\n%s\n",Eth_Buf);
           }
           send(peer_handle,send_data,strlen(send_data), 0);
           rt_thread_delay(RT_TICK_PER_SECOND/2);
      }
   }
}

//现在的问题是,如果先开PC机的以太网调试软件,监听8084端口,再开启MCU 可以连接的上,如果先开MCU,没有开PC机以太网调试软件,通过MCU串口会不断输出
Socket=0 connect fail
表示连接失败,我这边会先closesocket();再socket(AF_INET, SOCK_STREAM, 0)来产生新的socket,
如果再开启PC机的以太网调试软件,则在PC端连接后马上弹出 socket 100053错误,然后 MCU又新建一个SOCKET 连接,又100053错误,这样周而复始的,在调试软件是后面会有一堆MCU连接列表,MCU的端口从4098一直累加,我去网上搜索了一下,100053错误是由于TCP连接时一端处于半连接状态,是我开关TCP的SOCKET的方式错误,还是其他原因?各位能否帮我分析一下,先谢了

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

 楼主| 发表于 2010-12-14 21:58:39 | 显示全部楼层

(原文件名:1.JPG)

出0入0汤圆

发表于 2010-12-15 06:40:43 | 显示全部楼层
connect失败可以直接再做重新连接,而不用关闭scoket再去开一个socket。

出0入0汤圆

 楼主| 发表于 2010-12-15 08:43:58 | 显示全部楼层
谢谢ffxz的答复!我还想问一下,data_len = recv(socket_handle, Eth_Buf, sizeof(Eth_Buf), 0); 这个函数是阻塞的还是非阻塞的,我这个任务需要收、发TCP的数据,我发现调用上面的函数,只有有收到TCP数据包的时候才返回,如何做到非阻塞方式啊?

出0入0汤圆

发表于 2010-12-15 08:48:08 | 显示全部楼层
这个默认是阻塞的,如何实现非阻塞看看以太网串口的实现吧

出0入0汤圆

 楼主| 发表于 2010-12-17 09:15:05 | 显示全部楼层
后来和上位机开发人员商量,决定采用UDP通行方式,由于下位机上电时需要主动去连接上位机,需要收、发UDP数据包,我这种不同于例程上的UDP SERVER例程和UDP CLIENT例程,我的这个任务如下编写,有一个奇怪的问题,如果先发送一个数据包给上位机则无法再收数据包,如何做到收发独立,谢谢!
程序如下:

ALIGN(4) static const char send_data[] = "This is UDP Client from RT-Thread.\n"; /* 发送用到的数据 */

void rt_udp_rec_thread_entry(void* parameter)
{
        int socket_handle;
        struct sockaddr_in my_addr,remote_addr,client_addr;
        uint16_t port;
        W_B *TempW_B;
        int data_len;
        rt_err_t result;
        uint8_t *msg;
        uint16_t usTemp;
        uint8_t ucTemp;
        rt_uint32_t addr_len;
        fd_set readset;
        struct timeval to;
        uint32_t ulLoop=0;

    to.tv_sec =1;
    to.tv_usec =0;
         
        // 创建一个socket,类型是SOCK_DGRAM,UDP类型
        if ((socket_handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
        {
                #if(BSP_DEBUG>0)
                        //创建socket失败
                        rt_kprintf("Socket_rec create error\n");
                #endif
                while(1)
                {
                        rt_thread_delay(RT_TICK_PER_SECOND);
                }
        }

        //初始化预连接的服务端地址
        remote_addr.sin_family = AF_INET;

        port=Flash_Sys_Buf[FLASH_TCP_PORT+1]<<8;
        port+=Flash_Sys_Buf[FLASH_TCP_PORT];//8084端口
        remote_addr.sin_port = htons(port);

        TempW_B=(W_B *)&Flash_Sys_Buf[FLASH_TCP_SERVER_IP];//192.168.0.103
        remote_addr.sin_addr.s_addr= TempW_B->dword;

        rt_memset(&(remote_addr.sin_zero), 0, sizeof(remote_addr.sin_zero));

        //初始化自己的绑定地址
        my_addr.sin_family = AF_INET;

        port=Flash_Sys_Buf[FLASH_TCP_PORT+1]<<8;
        port+=Flash_Sys_Buf[FLASH_TCP_PORT];//8084端口
        my_addr.sin_port = htons(port);

        my_addr.sin_addr.s_addr= INADDR_ANY;//自己的端口

        rt_memset(&(my_addr.sin_zero), 0, sizeof(my_addr.sin_zero));

        //绑定socket到服务端地址
   if (bind(socket_handle,(struct sockaddr *)&my_addr,sizeof(struct sockaddr)) == -1)
   {
                   #if(BSP_DEBUG>0)
                        //绑定地址失败
                        rt_kprintf("Bind error\n");
                #endif
                while(1)
                {
                        rt_thread_delay(RT_TICK_PER_SECOND);
                }
               
   }
//           sendto(socket_handle, send_data, strlen(send_data),0,
//            (struct sockaddr *)&remote_addr, sizeof(struct sockaddr));//如果先发送一个数据包则无法收到数据包,屏蔽则不存在这个问题
        while(1)
        {
            addr_len = sizeof(struct sockaddr);
                FD_ZERO(&readset);
        FD_SET(socket_handle, &readset);

                if(lwip_select(socket_handle+1, &readset, 0, 0, 0)==0)
                {
                        continue;
                }
                data_len = recvfrom(socket_handle, Eth_Buf, sizeof(Eth_Buf),MSG_DONTWAIT,
                                     (struct sockaddr *)&client_addr, &addr_len);
                if( data_len > 0 )
        {
                        if(data_len==sizeof(Eth_Buf))
                        {
                                data_len--;       
                        }
                        Eth_Buf[data_len]='\0';
                        #if(BSP_DEBUG>0)
                                //输出接收的数据
                               rt_kprintf("\n(%s , %d) said : ",inet_ntoa(client_addr.sin_addr),
                          ntohs(client_addr.sin_port));
                                rt_kprintf("%s\n",Eth_Buf);
                        #endif
                }
                sendto(socket_handle, send_data, strlen(send_data),MSG_DONTWAIT,
                                (struct sockaddr *)&remote_addr, sizeof(struct sockaddr));
                        rt_thread_delay(RT_TICK_PER_SECOND);
                rt_thread_delay(RT_TICK_PER_SECOND);               
           }
}

出0入0汤圆

 楼主| 发表于 2010-12-17 09:23:07 | 显示全部楼层
这两幅图是屏蔽开始发送一个数据包和不屏蔽这个函数的UDP调试工具和串口调试工具图

开始不调用发送数据包函数 (原文件名:2.JPG)


开始调用发送数据包函数 (原文件名:3.JPG)
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-19 15:06

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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