服务器编程心得(四)—— 如何将socket设置为非阻塞模式

服务器编程心得(四)—— 如何将socket设置为非阻塞模式

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;

}

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

可以从哪里系统地学习到上述知识?

有同学私信问我,你这些知识从哪里学习的呢?

如果你是网络编程零基础或者觉得自己网络编程存在夹生饭问题,推荐看看尹圣雨的《TCP/IP 网络编程》,这本书同时兼顾 Windows 和 Linux 两个平台,使用的是 C 语言和操作系统的 Socket API,通过这本书你能学会常用的操作系统 Socket API 和常用的网络模型,认真学完之后,你不会再纠结同步异步、阻塞非阻塞等概念。

接着如果你想编写高性能的网络框架或者高效的服务,推荐游双老师的《Linux 高性能服务器编程》一书。

这两本书的获取方式可以参见这里:

https://mp.weixin.qq.com/s/JcaLLTBWiRKlfzZIyilNIQhttps://mp.weixin.qq.com/s/JcaLLTBWiRKlfzZIyilNIQ

当然,我自己也出版了一本书《C++ 服务器开发精髓》,在这本书凝聚了我从客户端到服务器、从 Windows 到 Linux 的经验总结,你还将从本书中系统地学习到 C++ 开发编译调试完整技术链、多线程编程技术、作者精心凝炼的20多个网络编程重难点知识、网络故障排查与定位知识、如何设计可兼容可扩展的通信协议、如何设计高性能网络框架、如何设计高性能服务框架、如何开发服务常用组件等知识。

https://mp.weixin.qq.com/s/b_KHMHzTP9XwHUuN32EI0Qhttps://mp.weixin.qq.com/s/b_KHMHzTP9XwHUuN32EI0Q

相关推荐

青橙VOGA V上手:不是每部手机都会投影
nba365直播现场视频直播

青橙VOGA V上手:不是每部手机都会投影

🌍 06-30 👁️ 5043
小米 6 的屏幕尺寸和機身長度
nba365直播现场视频直播

小米 6 的屏幕尺寸和機身長度

🌍 07-02 👁️ 2667
京东pop新店的运营思路是什么?商品如何优化?京东POP新店运营思路与商品优化实战指南