windows - ioctlsocket用法 - 在Win32中,有没有一种方法来测试套接字是否是非阻塞的?




ioctlsocket linux (2)

在Win32中,有没有一种方法来测试套接字是否是非阻塞的?

在POSIX系统下,我会做如下的事情:

int is_non_blocking(int sock_fd) {
    flags = fcntl(sock_fd, F_GETFL, 0);
    return flags & O_NONBLOCK;
}

但是,Windows套接字不支持fcntl()。 非阻塞模式是使用ioctl和FIONBIO 设置的 ,但是似乎没有办法使用ioctl 获得当前的非阻塞模式。

有没有其他的Windows调用,我可以用它来确定套接字当前是否处于非阻塞模式?


稍微长一点的答案是:不,但通常你会知道它是不是,因为它是相对明确的。

所有套接字都被阻塞,除非你用FIONBIO显式地ioctlsocket()它们ioctlsocket()或者交给WSAAsyncSelect或者WSAEventSelect 。 后两个函数“偷偷”把套接字改成非阻塞的。

既然你知道你是否已经调用了这三个函数之一,即使你不能查询状态,它仍然是已知的。 明显的例外是,如果该套接字来自某个第三方库,其中你不知道它到底是什么做的插座。

旁注:有趣的是,一个套接字可以同时被阻塞和重叠,这看起来并不直观,但是由于它们来自相反的范例(准备vs完成),所以它是有道理的。


以前,您可以调用WSAIsBlocking来确定这一点。 如果您正在管理遗留代码,这可能仍然是一个选项。

否则,您可以在套接字API上编写一个简单的抽象层。 由于所有的套接字默认都是阻塞的,所以你可以维护一个内部的标志,并通过你的API强制所有的套接字操作,所以你总是知道状态。

下面是一个跨平台的代码片段来设置/获取阻塞模式,虽然它不完全是你想要的:

/// @author Stephen Dunn
/// @date 10/12/15
bool set_blocking_mode(const int &socket, bool is_blocking)
{
    bool ret = true;

#ifdef WIN32
    /// @note windows sockets are created in blocking mode by default
    // currently on windows, there is no easy way to obtain the socket's current blocking mode since WSAIsBlocking was deprecated
    u_long flags = is_blocking ? 0 : 1;
    ret = NO_ERROR == ioctlsocket(socket, FIONBIO, &flags);
#else
    const int flags = fcntl(socket, F_GETFL, 0);
    if ((flags & O_NONBLOCK) && !is_blocking) { info("set_blocking_mode(): socket was already in non-blocking mode"); return ret; }
    if (!(flags & O_NONBLOCK) && is_blocking) { info("set_blocking_mode(): socket was already in blocking mode"); return ret; }
    ret = 0 == fcntl(socket, F_SETFL, is_blocking ? flags ^ O_NONBLOCK : flags | O_NONBLOCK);
#endif

    return ret;
}




nonblocking