LWIP之lwip_select函数使用

本测试基于lwip2.1.2。参考了CSDN博主「@则强」的文章

原文链接:https://blog.csdn.net/baidu_39191253/article/details/127630186

部分地方做了修改,增添了接收处理函数。方便调试。

此例子时采用lwip 非阻塞模式接收数据。然后通过select函数设置时间。间隔此时间查询接收数据然后再处理。接收到数据后直接转发出去。

平台采用GD32F470ZGT6的基于freertos的socket例程。(移植的lwip应该都可以用。包括正点原子,野火的例程。(tcp服务器例程) 编译时采用C99模式。

仅贴出tcp_ip任务的内容供参考。lwip_select函数这里主要用来做时间延迟。此函数会一直等待延迟时间,跟vTaskDelay函数类似。原因可跟踪内部函数,调用了二值信号量,应该是在等这个的时间。调试时间仓促。个别有理解错误的地方可以留言。函数测试通过。可以正常收发。

函数任务:

xTaskCreate(TCP_Server_task, "TCP_Server", DEFAULT_THREAD_STACKSIZE, NULL, TCP_SERVER_TASK_PRIO, NULL);

/*!
    \brief      TCP_Server task
    \param[in]  arg: user supplied argument
    \param[out] none
    \retval     none
*/
static void TCP_Server_task(void *arg)
{
    int ret;
    int sockfd = -1, newfd = -1;
    uint32_t len;
    int tcp_port = 8000;
    int recvnum;
    struct sockaddr_in svr_addr, clt_addr;
    char buf[50];

    /* bind to port 8000 at any interface */
    svr_addr.sin_family = AF_INET;
    svr_addr.sin_port = htons(tcp_port);
    svr_addr.sin_addr.s_addr = htons(INADDR_ANY);

    name_recv.length = 0;
    name_recv.done = 0;

    while(1) {
        /* create a TCP socket */
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if(sockfd < 0) {
            continue;
        }

        ret = bind(sockfd, (struct sockaddr *)&svr_addr, sizeof(svr_addr));
        if(ret < 0) {
            lwip_close(sockfd);
            sockfd = -1;
            continue;
        }                             
                unsigned long mode = 1;
                if(ioctlsocket(sockfd, FIONBIO, &mode) != 0) {
                    printf("SOCKET: failed to set socket non-blocking!\n");
                } 

        /* listen for incoming connections (TCP listen backlog = 1) */
        ret = listen(sockfd, 1);
        if(ret < 0) {
            lwip_close(sockfd);
            continue;
        }
                
    struct sockaddr_in sin;  /* bind socket address */
    socklen_t   sinlen;     /* length of address */
    fd_set  readfds;
    fd_set  errofds;
    int   ret, sock;                
                
    struct timeval timeout;
    int timeoutMs = 10;                
                
    while (1)
    {
/*
FD_ZERO(fd_set *fdset);              // 将set清零使集合中不含任何fd
FD_SET(int fd, fd_set *fdset);       // 将fd加入set集合
FD_CLR(int fd, fd_set *fdset);       // 将fd从set集合中清除
FD_ISSET(int fd, fd_set *fdset);     // 检测fd是否在set集合中,不在则返回0
调用FD_ZERO将一个 fd_set 变量的所有位设置为0。要开启描述符集中的一位,可以调用FD_SET。调用FD_CLR可以清除一位。最后,可以调用FD_ISSET测试描述符集中的一个指定位是否已打开。
*/    
        FD_ZERO(&readfds);
        FD_SET(sockfd, &readfds);
        FD_ZERO(&errofds);
        FD_SET(sockfd, &errofds);
        timeout.tv_sec = 1;
        timeout.tv_usec = 1000 * 0;//设置超时时间
        
        ret = select(sockfd + 1, &readfds, (fd_set *)0, &errofds, &timeout );
        if (ret == 0){//返回值等于0表示超时
            printf("wait connect\r\n");//等待连接,select函数跟vTaskDelay()函数类似,一直在此等待超时时间
      continue;
        }
        else if (ret < 0){//返回值小于于0表示出错
            printf("\n >>>>>> ret = %d\n",ret);
            break;
        }
        if (FD_ISSET(sockfd, &errofds))
        {
            printf("\n >>>>>> exit ok!\n");
            break;
        }
        sinlen = sizeof(sin);
        if (FD_ISSET(sockfd, &readfds))
        {
            printf("\n >>>>>>  read ok!\n");
            sock = accept(sockfd, (struct sockaddr *)&sin, &sinlen);
            if(sock < 0){
                    break;
            }
            else
            {
                while(1)//这里是接收函数,一直在这里循环
                {
                    //连接之后,开始接收数据
                    FD_ZERO(&readfds);
                    FD_SET(sock, &readfds);
                    FD_ZERO(&errofds);
                    FD_SET(sock, &errofds);
                    
                    int timeoutMs = 10;
                
                    timeout.tv_sec = timeoutMs / 1000;
                    timeout.tv_usec = (timeoutMs % 1000) * 1000;                    
                    
                    ret = select(sock + 1, &readfds, (fd_set *)0, &errofds, &timeout );
                    //printf("delay and ret = %d\r\n",ret);//测试函数到此位置时间 select函数跟vTaskDelay()函数类似,一直在此等待超时时间
                    if (ret>0)
                    {//返回值等于0表示超时
                            recvnum = recv(sock, buf, MAX_NAME_SIZE, 0);
                    }
                    if(recvnum>0)
                    {
                        memcpy(name_recv.bytes, buf, recvnum);
                        name_recv.length = recvnum;
                        send(sock, name_recv.bytes, name_recv.length, 0);
                        recvnum = 0;
                        name_recv.length = 0;
                    }
                }
            }
            
        }
    }                

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值