如何将套接字重置为阻塞模式(在将其设置为非阻塞模式后)?

16

我已经阅读过如何将套接字设置为非阻塞模式。

http://www.gnu.org/software/libc/manual/html_mono/libc.html#File-Status-Flags

以下是我的操作:

static void setnonblocking(int sock)
{
    int opts;

    opts = fcntl(sock,F_GETFL);
    if (opts < 0) {
        perror("fcntl(F_GETFL)");
        exit(EXIT_FAILURE);
    }
    opts = (opts | O_NONBLOCK);
    if (fcntl(sock,F_SETFL,opts) < 0) {
        perror("fcntl(F_SETFL)");
        exit(EXIT_FAILURE);
    }
    return;
}

如何将套接字设置回阻塞模式?我没有看到 O_BLOCK 标志?

谢谢。


看看这个答案是否有帮助。 - iammilind
3个回答

17
你尝试清除 O_NONBLOCK 标志了吗?
opts = opts & (~O_NONBLOCK)

7

这里有一个更具跨平台能力的解决方案:

bool set_blocking_mode(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 non_blocking = is_blocking ? 0 : 1;
    ret = NO_ERROR == ioctlsocket(socket, FIONBIO, &non_blocking);
#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;
}

Linux也有一个类似于WIN32 ioctlsocket()ioctl()函数。 - Alexis Wilke
@AlexisWilke 的确如此,但我的想法是 fcntl 的 API 明确说明了如何获取描述符的当前标志,虽然我本可以在第二次调用中使用它,但我试图避免读者进行潜在的第二个 API 查找。 - EntangledLoops
为什么要使用 const int & 参数? - MikeMB
@MikeMB 这只是我从代码库中提取此示例时的一个副产品。不必要的。 - EntangledLoops

0

清除标记的替代方法:

opts ^= O_NONBLOCK;

这将切换非阻塞标志,即如果当前已启用则禁用非阻塞。

8
如果已经很清楚了,切换开关会做错事情。因此,只需使用 opts &= ~O_NONBLOCK; 清除它即可。更简单、更安全。 - Craig McQueen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接