服务器编程心得(四)—— 如何将socket设置为非阻塞模式
admin
2023-03-10 20:41:06
0
  1. windows平台上无论利用socket()函数还是WSASocket()函数创建的socket都是阻塞模式的:
    
    SOCKET WSAAPI socket(
    _In_ int af,
    _In_ int type,
    _In_ int protocol
    );

SOCKET WSASocket(
In int af,
In int type,
In int protocol,
In LPWSAPROTOCOL_INFO lpProtocolInfo,
In GROUP g,
In DWORD dwFlags
);


linux平台上可以在利用socket()函数创建socket时指定创建的socket是异步的:

int socket(int domain, int type, int protocol);

在type的参数中设置SOCK_NONBLOCK标志即可,例如:

int s = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);

2. 另外,windows和linux平台上accept()函数返回的socekt也是阻塞的,linux另外提供了一个accept4()函数,可以直接将返回的socket设置为非阻塞模式:

int accept(int sockfd, struct sockaddr addr, socklen_t addrlen);

int accept4(int sockfd, struct sockaddr addr, socklen_t addrlen, int flags);

只要将accept4()最后一个参数flags设置成SOCK_NONBLOCK即可。

3. 除了创建socket时,将socket设置成非阻塞模式,还可以通过以下API函数来设置:

linux平台上可以调用fcntl()或者ioctl()函数,实例如下:

fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK);

ioctl(sockfd, FIONBIO, 1); //1:非阻塞 0:阻塞


参考: http://blog.sina.com.cn/s/blog_9373fc760101i72a.html

但是网上也有文章说(文章链接:http://blog.csdn.net/haoyu_linux/article/details/44306993),
linux下如果调用fcntl()设置socket为非阻塞模式,不仅要设置O_NONBLOCK模式,还需要在接收和发送数据时,需要使用MSG_DONTWAIT标志,即在recv,recvfrom和send,sendto数据时,将flag设置为MSG_DONTWAIT。是否有要进行这种双重设定的必要,笔者觉得没有这个必要。因为linux man手册上recv()函数的说明中关于MSG_DONTWAIT说明如下:

Enables nonblocking operation; if the operation would block, the call fails with the error EAGAIN or EWOULDBLOCK (this can also be enabled using the O_NONBLOCK flag  with the F_SETFL fcntl(2)).

通过这段话我觉得要么通过设置recv()函数的flags标识位为MSG_DONTWAIT,要么通过fcntl()函数设置O_NONBLOCK标识,而不是要同时设定。

windows上可调用ioctlsocket函数:

int ioctlsocket(
In SOCKET s,
In long cmd,
Inout u_long *argp
);

将cmd参数设置为 FIONBIO,*argp=0即设置成阻塞模式,而*argp非0即可设置成非阻塞模式。但是windows平台需要注意一个地方,如果你对一个socket调用了WSAAsyncSelect()或WSAEventSelect()函数后,你再调用ioctlsocket()函数将该socket设置为非阻塞模式,则会失败,你必须先调用WSAAsyncSelect()通过设置lEvent参数为0或调用WSAEventSelect()通过设置lNetworkEvents参数为0来分别禁用WSAAsyncSelect()或WSAEventSelect()。再次调用ioctlsocket()将该socket设置成阻塞模式才会成功。因为调用WSAAsyncSelect()或WSAEventSelect()函数会自动将socket设置成非阻塞模式。msdn上的原话是:

The WSAAsyncSelect and WSAEventSelect functions automatically set a socket to nonblocking mode. If WSAAsyncSelect or WSAEventSelect has been issued on a socket, then any attempt to use ioctlsocket to set the socket back to blocking mode will fail with WSAEINVAL.

To set the socket back to blocking mode, an application must first disable WSAAsyncSelect by calling WSAAsyncSelect with the lEvent parameter equal to zero, or disable WSAEventSelect by calling WSAEventSelect with the lNetworkEvents parameter equal to zero.

网址:https://msdn.microsoft.com/en-us/library/windows/desktop/ms738573(v=vs.85).aspx

4. 在看实际项目中以前一些前辈留下来的代码中,通过在一个循环里面调用fcntl()或者ioctlsocket()函数来socket的非阻塞模式的,代码如下:

for (;;)
{
#ifdef UNIX
on=1;
if (ioctlsocket(id, FIONBIO, (char *)&on) < 0)
#endif

#ifdef WIN32
unsigned long on_windows=1;
if (ioctlsocket(id, FIONBIO, &on_windows) < 0)
#endif

#ifdef VOS
int off=0;
if (ioctlsocket(id, FIONBIO, (char *)&off) <0)
#endif
{
if (GET_LAST_SOCK_ERROR() == EINTR)
continue;
RAISE_RUNTIME_ERROR("Can not set FIONBIO for socket");
closesocket(id);
return NULL;
}
break;
}


是否有必要这样做,有待考证。

相关内容

热门资讯

台风“红霞”成为今年以来登陆我... 根据中央气象台、广东省气象台消息,今年第12号台风“红霞”的中心已于今天(26日)3时50分前后在广...
业界热议AI安全护栏升级路径 ● 本报记者 郑萃颖 近年来,人工智能(AI)技术快速发展,相关安全问题也引发各界关注。接受中国证券...
RISC-V:当开源架构遇见智... 2026年,RISC-V正站在新的历史节点。智能体的崛起、数据中心算力范式的重构,RVA23、RIS...
网络电视不小心按成蓝屏了 1、重新检查并连接好电视机的信号源输入即可。2、检测电视机的信号源输入,如线路、接口松动,则重新连接...
问问海尔的冰箱款式怎么样 最佳回答 海尔冰箱的款式还是很多的,你可以去专卖店看一看,也可以去京东上或者是天猫上看一看,京东和天...
美的中央空调面板按了没反应 美的中央空调面板按了没反应可能有多种原因,以下是一些常见的解决方法:1. 检查电源:确保空调面板已接...
爆料称一款小阔直板新机定档明年... 继华为陆续推出两款阔折叠手机产品之后,网间曾曝光过关于 @OPPO 将推出自家首款阔直板机的消息。不...
中央空调按了开关没有反应是怎么... 原因可能是因为中央空调在使用前忘记通电或者连接空调的电路老化,接触不良,可以尝试将电源通电或者更换新...
美的数控热水器开关按了没反应 先看看是否电源出现问题而导致美帝数控热水器没有通电,按了开关才会没反应。如果家里的电源有电,那么就可...
华为领衔“超节点”,这些跨界公... 文丨惠凯 编辑丨承承 算力竞争已进入“超节点”时代。在此背景下,液冷需求激增,芯片企业加速IPO,制...