Winsock2 select():同一个套接字上的多个事件是可能的?

Posted

技术标签:

【中文标题】Winsock2 select():同一个套接字上的多个事件是可能的?【英文标题】:Winsock2 select(): multiple events on the same socket is possible? 【发布时间】:2017-08-10 18:03:57 【问题描述】:

根据this page:

select 函数返回套接字句柄的总数 已准备好并包含在 fd_set 结构中。

如果我在每个FD_SETs 中只添加一个(和相同的)SOCKET 并将它们传递给select,返回值是否可能大于 1?这意味着我必须在同一个套接字上处理多个事件。示例:

SOCKET someRandomSocket;

FD_SET readfds;
FD_SET writefds;
FD_SET exceptfds;

timeval timeout;
/* ...
Connecting someRandomSocket to another peer.
... */

FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&exceptfds);

FD_SET(someRandomSocket, &readfds);
FD_SET(someRandomSocket, &writefds);
FD_SET(someRandomSocket, &exceptfds);

int total = select(0, &readfds, &writefds, &exceptfds, &timeout);

/* total > 1 is possible? */
/* (FD_ISSET(someRandomSocket, &exceptfds) && (FD_ISSET(someRandomSocket, &readfds) || FD_ISSET(someRandomSocket, &writefds)) == true) possible? */

还有一个问题:是否有可能发生我必须同时处理同一个套接字上的异常和非异常事件?

【问题讨论】:

为什么不直接测试一下? @SergeyA - 如果我测试它并在每个select 之后得到total <= 1,这并不意味着total > 1 永远不会发生。另外,我真的不认为捕获select 会很容易,这将返回一个(readfdswritefds)和一个exceptfds,其中包含相同的套接字。无论如何,我希望我是错的,我会尝试测试它。 有一个简单的测试方法。只需获取可以写入和读取的相同套接字并将其放入选择中即可。看看你有什么。 【参考方案1】:

如果我在每个FD_SETs 中只添加一个(和相同的)SOCKET 并将它们传递给select,返回值是否可能大于 1?这意味着我必须在同一个套接字上处理多个事件。

无论select() 是否在返回值中多次计算相同的SOCKET(这很容易测试),您都应该忽略实际数字。 > 0 的返回值只是告诉您任何fd_sets 包含与请求的事件匹配的套接字(select() 修改fd_sets 以删除不匹配的套接字)。即使您知道套接字的总数,您仍然需要使用FD_ISSET() 检查各个套接字,因此返回值> 0 时的实际数字在实际处理中意义不大。只有 -1(错误)、0(超时)和 > 0(存在的事件)才有意义。

是的,一个套接字可以同时启用多个事件。例如,一个套接字可以同时可读和可写。

例如:

FD_SET readfds;
FD_SET writefds;
FD_SET exceptfds;

FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&exceptfds);

FD_SET(someRandomSocket, &readfds);
FD_SET(someRandomSocket, &writefds);
FD_SET(someRandomSocket, &exceptfds);

timeval timeout;
timeout.tv_sec = ...;
timeout.tv_usec = ...;

int total = select(0, &readfds, &writefds, &exceptfds, &timeout);

if (total == -1)

    // error in select() itself, handle as needed...

else if (total == 0)

    // timeout, handle as needed...

else

    if (FD_ISSET(someRandomSocket, &exceptfds) )
    
        // socket has inbound OOB data, or non-blocking connect() has failed, or some other socket error, handle as needed...
    

    if (FD_ISSET(someRandomSocket, &readfds) )
    
        // socket has inbound data, or has disconnected gracefully, handle as needed...
    

    if (FD_ISSET(someRandomSocket, &writefds) )
    
        // socket is writable, or non-blocking connect() has succeeded, handle as needed...
    

是否有可能发生我必须同时处理同一个套接字上的异常和非异常事件?

这取决于异常的性质。并非所有异常都是致命错误。

【讨论】:

谢谢!不知道只有value > 0有意义。 最后一个问题:我见过很多次,但不知道优雅断开到底是什么意思。这是否意味着另一个对等方在其SOCKET 上调用了closesocket() 这意味着对等方发送一个FIN 数据包以表明它不会再发送任何数据。该数据包由shutdown() 发送,如果shutdown() 尚未被调用,则closesocket() 发送。有关详细信息,请参阅 MSDN 上的 Graceful Shutdown, Linger Options, and Socket Closure。

以上是关于Winsock2 select():同一个套接字上的多个事件是可能的?的主要内容,如果未能解决你的问题,请参考以下文章

C++ WinSock2:连接()调用上的 WSA_INVALID_HANDLE

我用winsock2在C++中做了一个简单的套接字,我把recv函数放入一个变量中,它给出了一些奇怪的符号

Winsock2 - 如何使用 MSG_WAITALL 打开允许 ​​recv() 的 TCP 套接字?

如何中止winsock阻塞调用?

如果 winsock2 套接字是非阻塞的,与之关联的 SSL 对象是不是也会表现出非阻塞行为?

windows下socket编程小例子