使用select系统调用阻止recvfrom

时间:2013-09-04 18:36:22

标签: linux sockets select udp recv

我有一个UDP客户端,必须从两个不同的套接字接收 我正在使用select系统调用来复用recv调用。

但我发现客户端在第二次recv电话中被屏蔽了。

如何解决此问题?

struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
int activity;

FD_ZERO(&socketfds);
FD_SET(usocket,&socketfds);
max_sd = std::max(max_sd, usocket);
FD_SET(msocket,&socketfds);
max_sd = std::max(max_sd, msocket);
rset = socketfds;

do
{
      rset = socketfds;
      activity = select( max_sd + 1 , &rset , NULL , NULL , &timeout);
}
while(activity<0 && errno == EINTR);

if ((activity < 0) && (errno!=EINTR))
{
     printf("select error");
}
if(FD_ISSET(usocket, &socketfds))
{
      int len;
      printf("Receiving from unicast socket..\n");
      if((len = recvfrom(usocket, dataBuffer, dataLength, 0, (struct sockaddr *)  
   &clientAddr, &clen) < 0) )
     {
           printf("Error reading message \n");
           close(msocket);
           exit(-1);
     }
     else
     {
             printf("Size of message: %d\n", strlen(dataBuffer));
             handleMessage(dataBuffer);
     }
}
if(FD_ISSET(msocket, &socketfds))
{
     printf("Receiving from multicast socket..\n");
     if((recvfrom(msocket, dataBuffer, dataLength, 0, (struct sockaddr *)  
   &multicastClientAddr, &mlen) < 0) )
    {
       printf("Error reading message \n");
       close(msocket);
       exit(-1);
    }
    else
    {
      printf("Message from server:%s\n", dataBuffer);
      handleMessage(dataBuffer);
    }
}

3 个答案:

答案 0 :(得分:3)

您需要通过选择检查rset返回(已修改)以查看套接字是否已准备好读取 - 这些位始终会在socketfds中设置,因为这是您的主套接字等待。所以改变

if(FD_ISSET(Xsocket, &socketfds))

行到

if(FD_ISSET(Xsocket, &rset))

答案 1 :(得分:1)

我认为,问题在于你没有考虑超时,当超时时选择返回0。在这种情况下,当返回0时,我不知道rset结构将如何,可能是未分解的或未触及的。如果你想等无穷大,就把NULL替换为超时。

答案 2 :(得分:1)

您应该更改do-while循环的条件。仅当存在某个事件时,Select才会返回非零值(具有事件的fds的数量)。在您的情况下,它将返回已读取事件的fds数。因此,如果其中一个fds有一个读事件,那么select()将返回1,如果两个都有读事件,那么select将返回2.如果(activity == 0),那么hte的数量与读事件是零,所以如果你调用recvfrom(),那自然会阻止。

while(activity <= 0 && errno == EINTR);