简体   繁体   English

套接字select()在Windows中工作,在Linux中超时

[英]Socket select() works in Windows and times out in Linux

I'm porting a windows network application to linux and faced a timeout problem with select call on linux. 我正在将Windows网络应用程序移植到linux,并且在linux上选择调用时遇到超时问题。 The following function blocks for the entire timeout value and returns while I checked with a packet sniffer that client has already sent the data. 以下函数将阻止整个超时值,并在我用包嗅探器检查客户端已发送数据时返回。

int recvTimeOutTCP( SOCKET socket, long sec, long usec )
{
  struct timeval timeout;
  fd_set fds;.

  timeout.tv_sec = sec;
  timeout.tv_usec = usec;
  FD_ZERO( &fds );
  FD_SET( socket, &fds );

  // Possible return values:
  // -1: error occurred
  // 0: timed out
  // > 0: data ready to be read
  cerr << "Waiting on fd " << socket << endl;
  return select(1, &fds, 0, 0, &timeout);
}

I think the first parameter to select() should be socket+1 . 我认为select()的第一个参数应该是socket+1

You really should use another name as socket also is used for other things. 您确实应该使用其他名称,因为socket也用于其他用途。 Usually sock is used. 通常使用sock

From the man page of select: 从选择的手册页中:

int select(int nfds,
           fd_set* restrict readfds,
           fd_set* restrict writefds,
           fd_set* restrict errorfds, 
           struct timeval* restrict timeout);

The first nfds descriptors are checked in each set; 在每个集合中检查第一个nfds描述符; ie, the descriptors from 0 through nfds-1 in the descriptor sets are examined. 也就是说,检查描述符集中从0到nfds-1的描述符。

Thus the first parameter to select should be socket + 1. 因此,要选择的第一个参数应该是socket + 1。

return select(socket + 1, &fds, 0, 0, &timeout);

select on Windows ignores the first parameter. Windows上的select忽略第一个参数。 From MSDN: 从MSDN:

C++
int select(
  __in     int nfds,
  __inout  fd_set *readfds,
  __inout  fd_set *writefds,
  __inout  fd_set *exceptfds,
  __in     const struct timeval *timeout
);

Parameters

nfds [in]

    Ignored. The nfds parameter is included only for
    compatibility with Berkeley sockets.
...

The issue is that the fd_set in linux is a bit array ( originally it was just a int, but then you could only watch the first 16 io's of your process ). 问题是Linux中的fd_set是一个位数组(起初它只是一个int,但随后您只能观看进程的前16个io)。 In windows fd_set is an array of sockets with a length at the front (which is why windows doesn't need to know how many bits to watch). 在Windows中,fd_set是一个套接字数组,其长度在前面(这就是为什么Windows不需要知道要监视多少位的原因)。

The poll() function takes an array of records to watch on linux and has other benefits which make it a better choice than select(). poll()函数接受一系列记录以在Linux上观看,并且具有其他优点,这使其比select()更好。

int recvTimeOutTCP( SOCKET socket, long msec )
{
    int iret ;
    struct polldf   sockpoll ;

    sockpoll.fd= socket ;
    sockpoll.events= POLLIN ;

    return poll(& sockpoll, 1, msec) ;
}   

The first parameter to select (...) is the number of file descriptor to check in the set. 选择的第一个参数(...)是要在集合中检查的文件描述符的数量。 Your call is telling it to only look at file descriptor 0, which is almost certainly not what socket is set to. 您的呼叫告诉它仅查看文件描述符0,这几乎可以肯定不是套接字设置的内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM