在Win32中,有没有办法测试套接字是否是非阻塞的?

时间:2021-11-25 21:46:29

In Win32, is there a way to test if a socket is non-blocking?

在Win32中,有没有办法测试套接字是否是非阻塞的?

Under POSIX systems, I'd do something like the following:

在POSIX系统下,我会做类似以下的事情:

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

However, Windows sockets don't support fcntl(). The non-blocking mode is set using ioctl with FIONBIO, but there doesn't appear to be a way to get the current non-blocking mode using ioctl.

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

Is there some other call on Windows that I can use to determine if the socket is currently in non-blocking mode?

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

2 个解决方案

#1


6  

A slightly longer answer would be: No, but you will usually know whether or not it is, because it is relatively well-defined.

稍微长一点的答案是:不,但你通常会知道它是否是,因为它的定义相对较好。

All sockets are blocking unless you explicitly ioctlsocket() them with FIONBIO or hand them to either WSAAsyncSelect or WSAEventSelect. The latter two functions "secretly" change the socket to non-blocking.

所有套接字都是阻塞的,除非您使用FIONBIO显式地将它们ioctlsocket()或将它们移交给WSAAsyncSelect或WSAEventSelect。后两个函数“秘密”将套接字更改为非阻塞。

Since you know whether you have called one of those 3 functions, even though you cannot query the status, it is still known. The obvious exception is if that socket comes from some 3rd party library of which you don't know what exactly it has been doing to the socket.

既然您知道是否已经调用了这三个函数中的一个,即使您无法查询状态,它仍然是已知的。明显的例外是,如果该套接字来自某些第三方库,您不知道它对套接字做了什么。

Sidenote: Funnily, a socket can be blocking and overlapped at the same time, which does not immediately seem intuitive, but it kind of makes sense because they come from opposite paradigms (readiness vs completion).

旁注:有趣的是,套接字可以同时阻塞和重叠,这看起来并不直观,但它有点合理,因为它们来自相反的范例(准备与完成)。

#2


2  

Previously, you could call WSAIsBlocking to determine this. If you are managing legacy code, this may still be an option.

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

Otherwise, you could write a simple abstraction layer over the socket API. Since all sockets are blocking by default, you could maintain an internal flag and force all socket ops through your API so you always know the state.

否则,您可以在套接字API上编写一个简单的抽象层。由于默认情况下所有套接字都是阻塞的,因此您可以维护内部标志并强制所有套接字操作通过您的API,以便您始终了解状态。

Here is a cross-platform snippet to set/get the blocking mode, although it doesn't do exactly what you want:

这是一个用于设置/获取阻止模式的跨平台代码段,尽管它并不完全符合您的要求:

/// @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;
}

#1


6  

A slightly longer answer would be: No, but you will usually know whether or not it is, because it is relatively well-defined.

稍微长一点的答案是:不,但你通常会知道它是否是,因为它的定义相对较好。

All sockets are blocking unless you explicitly ioctlsocket() them with FIONBIO or hand them to either WSAAsyncSelect or WSAEventSelect. The latter two functions "secretly" change the socket to non-blocking.

所有套接字都是阻塞的,除非您使用FIONBIO显式地将它们ioctlsocket()或将它们移交给WSAAsyncSelect或WSAEventSelect。后两个函数“秘密”将套接字更改为非阻塞。

Since you know whether you have called one of those 3 functions, even though you cannot query the status, it is still known. The obvious exception is if that socket comes from some 3rd party library of which you don't know what exactly it has been doing to the socket.

既然您知道是否已经调用了这三个函数中的一个,即使您无法查询状态,它仍然是已知的。明显的例外是,如果该套接字来自某些第三方库,您不知道它对套接字做了什么。

Sidenote: Funnily, a socket can be blocking and overlapped at the same time, which does not immediately seem intuitive, but it kind of makes sense because they come from opposite paradigms (readiness vs completion).

旁注:有趣的是,套接字可以同时阻塞和重叠,这看起来并不直观,但它有点合理,因为它们来自相反的范例(准备与完成)。

#2


2  

Previously, you could call WSAIsBlocking to determine this. If you are managing legacy code, this may still be an option.

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

Otherwise, you could write a simple abstraction layer over the socket API. Since all sockets are blocking by default, you could maintain an internal flag and force all socket ops through your API so you always know the state.

否则,您可以在套接字API上编写一个简单的抽象层。由于默认情况下所有套接字都是阻塞的,因此您可以维护内部标志并强制所有套接字操作通过您的API,以便您始终了解状态。

Here is a cross-platform snippet to set/get the blocking mode, although it doesn't do exactly what you want:

这是一个用于设置/获取阻止模式的跨平台代码段,尽管它并不完全符合您的要求:

/// @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;
}