首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在C linux中使用UDP服务器的线程时阻止recvfrom()阻塞?

如何在C linux中使用UDP服务器的线程时阻止recvfrom()阻塞?
EN

Stack Overflow用户
提问于 2022-06-22 13:37:45
回答 1查看 283关注 0票数 -1

我在两台计算机之间实现服务器-客户机,其思想是读取从连接到PC3的输入,并将其发送到PC4以及返回方式(来自连接的从P4的输入并将其发送到PC3)。

服务器端:

代码语言:javascript
复制
client:
static void FSoEThread()
{
   struct timeval time1;

   uint8_t  pdu_in_local[sizeof(pdu_in)];
   uint8_t  pdu_out_local[sizeof(pdu_out)];

   uint8_t  pdu_in_tmp[sizeof(pdu_in)];
   uint8_t  pdu_out_tmp[sizeof(pdu_out)];

   FILE *fp;
   fp = fopen("Log.txt", "w");//opening file.
   SerialPort sp(MODEMDEVICE);
   
    int socket_desc;
    struct sockaddr_in server_addr;
    unsigned int  server_message[255], client_message[255];
    socklen_t server_struct_length = sizeof(server_addr);
;

   printf("Thread_quit\n");

     while(!thread_quit){

    
        std::vector<uint8_t> uart_in(10);
        sp.Read(uart_in);

       if(1){
        switch(ecatGetMasterState())
        {
        default:

            break;
        case _UNKNOWN:
        case _INIT:
        case _PREOP:
        case _SAFEOP:
            break;
        case eEcatState_OP:
        {

            {
                uint8_t buf[sizeof(pdu_in)]; // In data comes from Slave
                if(uart_in.size() == 10){
                    PD_mutex.lock();
                    memcpy(pdu_out,&uart_in.data()[4],sizeof(pdu_out));//out data coming from Master to the Slave
                    memcpy(pdu_out_local,&uart_in.data()[4],sizeof(pdu_out));

                    memcpy(buf,pdu_in,sizeof(pdu_in));
                    memcpy(pdu_in_local,pdu_in,sizeof(pdu_in));

                    PD_mutex.unlock();
                        printf("\n");
                    sp.Write(buf,sizeof(pdu_in));
        }
        }
            

            gettimeofday(&time1,NULL);

            if(memcmp(pdu_in_tmp,pdu_in_local,sizeof(pdu_in)) != 0){
                memcpy(pdu_in_tmp,pdu_in_local,sizeof(pdu_in));

                fprintf(fp,"[%05d.%06d]in  %02x %02x %02x %02x %02x %02x\n",time1.tv_sec,time1.tv_usec,
                        (unsigned int)pdu_in_tmp[0],
                        (unsigned int)pdu_in_tmp[1],
                        (unsigned int)pdu_in_tmp[2],
                        (unsigned int)pdu_in_tmp[3],
                        (unsigned int)pdu_in_tmp[4],
                    (unsigned int)pdu_in_tmp[5]
                );
            unsigned int *PDU_UDP_IN = (unsigned int*)pdu_in_tmp;  
            // Create socket:
            socket_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
            if(socket_desc < 0){
            printf("Error while creating socket\n");
            exit(1);
            }

            // Clean buffers:
            memset(server_message, 0, sizeof(server_message));
            memset(client_message, 0, sizeof(client_message));


            // Set port and IP:
            server_addr.sin_family = AF_INET;
            server_addr.sin_port = htons(2000);
            server_addr.sin_addr.s_addr = inet_addr("10.100.20.54");

            printf("sending\n");
            // Send the message to server:
            if(sendto(socket_desc, PDU_UDP_IN, sizeof(PDU_UDP_IN), 0,
             (struct sockaddr*)&server_addr, server_struct_length) < 0){
            printf("Unable to send message\n");
            exit(1);
            }

            printf("sendto: msg send to IPC4 :\t%x\n",*PDU_UDP_IN);    

                socklen_t server_struct_length = sizeof(server_addr);
            
                
            //recvfrom(socket_desc, server_message, sizeof(server_message), 0,(struct sockaddr*)&server_addr, &server_struct_length);
            //if(int errn_ = recvfrom(socket_desc, server_message, sizeof(server_message), 0,(struct sockaddr*)&server_addr, &server_struct_length) < 0){
            //printf("Error while receiving server's msg\n");
            //printf("n=%d, Errno%d\n",errn_,errno);
            //exit(1);
            //}
            printf("Recved\n");
            printf("MSG from IPC4:\t%x\n",*server_message);    
            close(socket_desc);
            }

            if(memcmp(pdu_out_tmp,pdu_out_local,sizeof(pdu_out)) != 0){
                memcpy(pdu_out_tmp,pdu_out_local,sizeof(pdu_out));
    
                fprintf(fp,"[%05d.%06d]out %02x %02x %02x %02x %02x %02x\n",time1.tv_sec,time1.tv_usec,
                        (unsigned int)pdu_out_tmp[0],
                        (unsigned int)pdu_out_tmp[1],
                        (unsigned int)pdu_out_tmp[2],
                        (unsigned int)pdu_out_tmp[3],
                        (unsigned int)pdu_out_tmp[4],
                        (unsigned int)pdu_out_tmp[5]
                );
    }


        }
    }
        }
     }


   pthread_exit(NULL);
}

这一边如果运作良好..。它可以收发..。

现在发生问题的客户端..。假设我在客户端(PC3)的这端注释/删除recvfrom,..all工作正常(服务器端recvfrom和sendto工作,我获得数据并可以发送数据),当我尝试接收数据时(再次在客户端使用recvfrom函数)数据被交换了4次,然后客户机和服务器都不再做任何事情了->,我将陷入死锁,两者都在RECVFROM中被阻塞。

代码语言:javascript
复制
static void FSoEThread()
{
   struct timeval time1;

   uint8_t  pdu_in_local[sizeof(pdu_in)];
   uint8_t  pdu_out_local[sizeof(pdu_out)];

   uint8_t  pdu_in_tmp[sizeof(pdu_in)];
   uint8_t  pdu_out_tmp[sizeof(pdu_out)];



    int socket_desc;
    struct sockaddr_in server_addr, client_addr;
    unsigned int server_message[255], client_message[255];
            socklen_t client_struct_length = sizeof(client_addr);


       // Clean buffers:
       memset(server_message, '\0', sizeof(server_message));
       memset(client_message, '\0', sizeof(client_message));
       FILE *fp;
       fp = fopen("Llog.txt", "w");//opening file.
       long save_fd;
    SerialPort sp(MODEMDEVICE);


   printf("thread_quit\n");

           while(!thread_quit){

        std::vector<uint8_t> uart_in(10);
        sp.Read(uart_in);

       if(1){
        switch(ecatGetMasterState())
        {
        default:
            break;
        case _UNKNOWN:
        case _INIT:
        case _PREOP:
        case _SAFEOP:
            break;
        case eEcatState_OP:    
        {
            {
                uint8_t buf[sizeof(pdu_in)];
                if(uart_in.size() == 10){
                    PD_mutex.lock();
                    memcpy(pdu_out,&uart_in.data()[4],sizeof(pdu_out));
                    memcpy(pdu_out_local,&uart_in.data()[4],sizeof(pdu_out));

                    memcpy(buf,pdu_in,sizeof(pdu_in));
                    memcpy(pdu_in_local,pdu_in,sizeof(pdu_in));
                    PD_mutex.unlock();

                    sp.Write(buf,sizeof(pdu_in));

                }
            }

            gettimeofday(&time1,NULL);

            if(memcmp(pdu_in_tmp,pdu_in_local,sizeof(pdu_in)) != 0){
                memcpy(pdu_in_tmp,pdu_in_local,sizeof(pdu_in));

                fprintf(fp,"[%05d.%06d]in  %02x %02x %02x %02x %02x %02x\n",time1.tv_sec,time1.tv_usec,
                        (unsigned int)pdu_in_tmp[0],
                        (unsigned int)pdu_in_tmp[1],
                        (unsigned int)pdu_in_tmp[2],
                        (unsigned int)pdu_in_tmp[3],
                        (unsigned int)pdu_in_tmp[4],
                        (unsigned int)pdu_in_tmp[5]
                );
            
            unsigned int * PDU_UDP_IN = (unsigned int*)pdu_in_tmp;
            printf("in \t%X\n",*PDU_UDP_IN);
                           // Create UDP socket:
            socket_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
            if(socket_desc < 0){
            printf("Error while creating socket\n");
            exit(1);
            }
            // Set port and IP:
            server_addr.sin_family = AF_INET;
            server_addr.sin_port = htons(2000);
            server_addr.sin_addr.s_addr = inet_addr("10.100.20.54");

            // Bind to the set port and IP:
            if(bind(socket_desc, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0){

            exit(1);
            }

            //printf("Listening for incoming messages...\n\n");
            // Receive client's message:
            
            printf("Recving\n");
            if (recvfrom(socket_desc, client_message, sizeof(client_message), 0,(struct sockaddr*)&client_addr, &client_struct_length) < 0){
            //printf("Couldn't receive\n");
            //continue;
            }
            printf("Received\n");
            //     inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

            printf("msg from IPC3:\t%x\n", *client_message);

            // Respond to client:
            
            printf(" sending\n");
            // strcpy(server_message, client_message);
            socklen_t client_struct_length = sizeof(client_addr);
            if (sendto(socket_desc, PDU_UDP_IN, sizeof(PDU_UDP_IN), 0,
             (struct sockaddr*)&client_addr, client_struct_length) < 0){
            printf("Can't send\n");
            exit(EXIT_FAILURE);
            }
            printf(" sent\n");
            // Close the socket:
            close(socket_desc);
            }

            if(memcmp(pdu_out_tmp,pdu_out_local,sizeof(pdu_out)) != 0){
                memcpy(pdu_out_tmp,pdu_out_local,sizeof(pdu_out));

                fprintf(fp,"[%05d.%06d]out %02x %02x %02x %02x %02x %02x\n",time1.tv_sec,time1.tv_usec,
                        (unsigned int)pdu_out_tmp[0],
                        (unsigned int)pdu_out_tmp[1],
                        (unsigned int)pdu_out_tmp[2],
                        (unsigned int)pdu_out_tmp[3],
                        (unsigned int)pdu_out_tmp[4],
                        (unsigned int)pdu_out_tmp[5]
                );

            }

        }
        }
        }
     }

   pthread_exit(NULL);
}

我的问题:

我在这里做错什么了吗?

有什么办法可以更容易地解决这个问题吗?我读过关于select的文章,但我不知道当我使用两台不同线程的PC时,它是否有效

3-我尝试使用像MSG_DONTWAIT这样的标志,尝试使用setsockopt() .

有办法真正调试这种情况吗?

我真的很感激你的回答

程序是真正的big...those是UDP实现的一部分。in是用C/C++编写的,其他部分都很完美,问题只是知道如何使UDP停止阻塞。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-06-22 16:16:42

  1. ,我是不是做错什么了?

你似乎对UDP有很多种族条件和误解。

如果服务器向客户端发送数据报,当客户端没有套接字绑定时,数据报就会丢失。直到晚些时候才排队。在反向路径上也有同样的问题。

如果服务器和客户端套接字都处于打开状态,那么至少会有数据报排队,直到缓冲区被填满为止。这给了你一个很好的机会去阅读一条信息,以免它永远丢失。

尽管如此,在这里阻塞recvfrom仍然是一个错误。数据报可能会因为网络拥塞而丢失,而无限期挂起并不是一个好的响应。

  1. 有没有更简单的方法来解决这个问题?我读过关于select的文章,但我不知道当我使用两台不同线程

的PC时,它是否有效

如果您不知道如何使用非阻塞的UDP来处理这个问题(或者相当合理地不想花费所需的时间),只需使用TCP,并记住设置TCP_NODELAY

我一直在用像setsockopt()这样的标志尝试使用

尝试找到TCP/IPIllustratedVol.1的第二次拷贝,如果可能的话,旧的Stevens版本(它缺少更新的更新,但涵盖的基础很好,序列图更好的IIRC)。通过尝试和错误来理解这件事是痛苦的。

  1. 有办法真正调试这种情况吗?

  • 运行wireshark或tcpdump或其他数据包捕获工具
  • strace下运行客户端和服务器,并确保显示所有的套接字系统,并具有准确(希望是同步良好)时间戳

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72716562

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档