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

发布于 2024-10-28 07:43:33 字数 374 浏览 5 评论 0原文

在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 上是否有其他调用可以用来确定套接字当前是否处于非阻塞模式?

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

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

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.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

天涯沦落人 2024-11-04 07:43:34

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

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

由于您知道是否调用了这 3 个函数之一,因此即使您无法查询状态,它仍然是已知的。明显的例外是,如果该套接字来自某个第三方库,而您不知道它到底对套接字做了什么。

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

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.

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).

红颜悴 2024-11-04 07:43:34

以前,您可以调用 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;
}

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

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.

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;
}
红墙和绿瓦 2024-11-04 07:43:34

我同意已接受的答案,没有官方方法可以确定 Windows 上套接字的阻塞状态。如果你从第三方获得套接字(假设你是一个 TLS 库,并且从上层获得套接字),你无法决定它是否处于阻塞状态。

尽管如此,我还是有一个有效的、非官方的、有限的解决方案来解决这个问题,它对我来说很长时间。

我尝试从套接字读取 0 个字节。如果它是阻塞套接字,它将返回 0,如果它是非阻塞套接字,它将返回 -1 并且 GetLastError 等于 WSAEWOULDBLOCK。

int IsBlocking(SOCKET s)
{
    int r = 0;
    unsigned char b[1];
    r = recv(s, b, 0, 0);
    if (r == 0)
        return 1;
    else if (r == -1 && GetLastError() == WSAEWOULDBLOCK)
        return 0;
    return -1; /* In  case it is a connection socket (TCP) and it is not in connected state you will get here 10060 */
}

注意事项:

  • 适用于 UDP 套接字
  • 适用于已连接的 TCP 套接字
  • 不适用于未连接的 TCP 套接字

I agree with the accepted answer, there is no official way to determine the blocking state of a socket on Windows. In case you get a socket from a third party (let's say, you are a TLS library and you get the socket from upper layer) you cannot decide if it is in blocking state or not.

Despite this I have a working, unofficial and limited solution for the problem which works for me for a long time.

I attempt to read 0 bytes from the socket. In case it is a blocking socket it will return 0, in case it is a non-blocking it will return -1 and GetLastError equals WSAEWOULDBLOCK.

int IsBlocking(SOCKET s)
{
    int r = 0;
    unsigned char b[1];
    r = recv(s, b, 0, 0);
    if (r == 0)
        return 1;
    else if (r == -1 && GetLastError() == WSAEWOULDBLOCK)
        return 0;
    return -1; /* In  case it is a connection socket (TCP) and it is not in connected state you will get here 10060 */
}

Caveats:

  • Works with UDP sockets
  • Works with connected TCP sockets
  • Doesn't work with unconnected TCP sockets
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文