Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >(四) 如何将socket设置为非阻塞模式

(四) 如何将socket设置为非阻塞模式

作者头像
范蠡
发布于 2018-04-04 07:19:23
发布于 2018-04-04 07:19:23
4.7K00
代码可运行
举报
运行总次数:0
代码可运行

1. windows平台上无论利用socket()函数还是WSASocket()函数创建的socket都是阻塞模式的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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是异步的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int socket(int domain, int type, int protocol);  

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int s = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);  

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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()函数,实例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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的非阻塞模式的,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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;  
}  

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-03-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 高性能服务器开发 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
UDP服务recvfrom函数设置非阻塞
本文先介绍我查看了的2篇文章,然后介绍linux 和windows 下的非阻塞设置。最后是非阻塞情况下接收情况的判断。
全栈程序员站长
2022/09/15
2.4K0
ioctlsocket() 用法 socket recvfrom 阻塞 非阻塞 设置
不知道大家有没有遇到过这种情况,当socket进行TCP连接的时候(也就是调用connect时),一旦网络不通,或者是ip地址无效,就可能使整个线程阻塞。一般为30秒(我测的是20秒)。如果设置为非阻塞模式,能很好的解决这个问题,我们可以这样来设置非阻塞模式:
战神伽罗
2019/08/29
3.8K0
从linux源码看socket的阻塞和非阻塞 顶
笔者一直觉得如果能知道从应用到框架再到操作系统的每一处代码,是一件Exciting的事情。 大部分高性能网络框架采用的是非阻塞模式。笔者这次就从linux源码的角度来阐述socket阻塞(block)和非阻塞(non_block)的区别。 本文源码均来自采用Linux-2.6.24内核版本。
无毁的湖光-Al
2018/08/14
3.6K0
从linux源码看socket的阻塞和非阻塞
                                                    顶
Socket
Socket模块简单理解就是对socket套接字的封装,当然不是简单的对socket套接字接口的封装,还需要实现一些方法,比如启动非阻塞通信、创建客户端连接、创建服务器连接等。
二肥是只大懒蓝猫
2024/02/07
1580
Socket
C++中的socket编程常用接口
socket() 函数是进行网络编程的基础,它用于创建一个新的套接字(socket)。套接字是网络通信的端点,可以用于在不同计算机之间传输数据。下面是对 socket() 函数的详细解释:
薄荷冰
2024/07/19
1630
非阻塞recvfrom的设置[通俗易懂]
分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
全栈程序员站长
2022/09/15
2K0
linux网络编程系列(七)--如何将socket设置成非阻塞的,非阻塞socket与阻塞的socket在收发数据上的区别
socket函数创建socket默认是阻塞的,也可以增加选项将socket设置为非阻塞的:
cpp加油站
2021/04/16
3.5K0
linux网络编程系列(七)--如何将socket设置成非阻塞的,非阻塞socket与阻塞的socket在收发数据上的区别
网络通信基础重难点解析 08 :connect 函数在阻塞和非阻塞模式下的行为
在 socket 是阻塞模式下 connect 函数会一直到有明确的结果才会返回(或连接成功或连接失败),如果服务器地址“较远”,连接速度比较慢,connect 函数在连接过程中可能会导致程序阻塞在 connect 函数处好一会儿(如两三秒之久),虽然这一般也不会对依赖于网络通信的程序造成什么影响,但在实际项目中,我们一般倾向使用所谓的异步的 connect 技术,或者叫非阻塞的 connect。这个流程一般有如下步骤:
范蠡
2019/04/29
1.8K0
使用epoll时需要将socket设为非阻塞吗?
一、结论 提出这个问题说明对网络编程的一些基础原理未搞明白,先说下结论: 一个 socket 是否设置为阻塞模式,只会影响到 connect/accept/send/recv 等四个 socket API 函数,不会影响到 select/poll/epoll_wait 函数,后三个函数的超时或者阻塞时间是由其函数自身参数控制的。 二、原理分析 下面详细的解释,为了方便解释,在这之前我们先明确几个基础概念: connfd:创建 socket,主动发起连接的一端(客户端),该端调用 connect 函数主动发起
范蠡
2022/04/21
2.5K0
使用epoll时需要将socket设为非阻塞吗?
从内核看socketpair的实现(基于5.9.9)
Unix域支持服务器、客户端的模式,这种模式的好处就是任意进程都可以和服务器进程通信,这种模式通常需要一个文件路径作为地址,使得任意进程都能通过该文件路径标识找到服务器地址。而socketpair虽然也类似,但它不需要地址的概念,因为它用于有继承关系的进程间通信,通常是主进程调用socketpair拿到两个fd,然后fork出子进程,这样两个进程就可以通信了,不需要寻址的过程,也就不需要地址的概念了。下面我从内核角度看看socketpair的实现。
theanarkh
2021/07/08
6050
从内核看socketpair的实现(基于5.9.9)
Linux系统下socket编程之socket接口介绍(一)
其实在写这篇文章开始之前,原本想打算先介绍一下TCP/IP协议的内容,但是在网上看了一些博客,大概都讲的差不多,随便找几篇博客来看(https://developer.51cto.com/art/201906/597961.htm),你就会对这个协议有一个大概的了解(有些地方或许读者和我一样可能也看的不是很明白,但是这对编程阻碍不大),所以我也不打算写这个了(理由是,自己也比较菜,只要大概了解一下这部分内容就行,在日后学习或者工作当中遇到什么不理解的地方再去深入学,比较有针对性;所以侧重点还是在编程上,最终实现理论转到实践当中去,才是王道)。不过经典的TCP三次握手和四次挥手告别,这个基本你必须要明白,这里简单介绍一下,那么就开始今天的内容了。
用户6280468
2022/03/18
3K0
Linux系统下socket编程之socket接口介绍(一)
ACCEPT()和ACCEPT4()
accept() 系统调用应用于可连接套接口类型 ( SOCK_STREAM, SOCK_SEQPACKET)。它取出在监听套接口 sockfd请求队列里的第一个连接,新建一个已连接的套接口,并且返回一个引用该套接口新的文件描述符。新建的套接口不处于监听状态。原始的套接口 sockfd 没有受到影响。
Java架构师必看
2021/03/22
1.9K0
网络编程常见问题总结
在网络程序中遇到的一些问题进行了总结, 这里主要针对的是我们常用的TCP socket相关的总结, 可能会存在错误, 有任何问题欢迎大家提出.
阳光岛主
2019/02/19
8790
浅谈 non-blocking I/O Multiplexing + poll/epoll 的正确使用
s1mba
2017/12/28
2K0
浅谈 non-blocking I/O Multiplexing + poll/epoll  的正确使用
Linux下Socket编程(三)——非阻塞select的使用简介
阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回。 使用Select就可以完成非阻塞(所谓非阻塞方式non- block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高)方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况读写或是异常。
用户2929716
2018/08/23
4.3K0
Linux下Socket编程(三)——非阻塞select的使用简介
从内核角度看怎么设置connect超时
我们在编写网络程序时,通常需要连接其他服务端(如微服务之间的通信),这时就需要通过调用 connect 函数来连接服务端。但我们发现 connect 函数并没有提供超时的设置,而在 Linux 系统中,connect 的默认超时时间为75秒。所以,在连接不上服务端的情况下,我们需要等待75秒,这对我们不能接受的。
用户7686797
2021/04/08
2.1K0
【Linux】accept(2) - Linux man page
accept(2): accept connection on socket - Linux man page (die.net)
阿东
2023/07/21
3480
Java NIO套接字【源码笔记】
本文以代码示例跟踪调用Native函数,看下原型函数的具体释义。例子中“客户端”从文件test02.tmp读取内容后,通过socket发送到“服务端”后写入test01.tmp文件中。
瓜农老梁
2020/02/26
9060
socket在windows和Linux下的区别
1)头文件  windows下winsock.h/winsock2.h  linux下sys/socket.h    错误处理:errno.h  2)初始化  windows下需要用WSAStartup WSADATA wsaData;         err = WSAStartup(0x202,&wsaData); if ( err != 0 ) { return 0; } else if ( LOBYTE( wsaData.wVersion )
老白
2018/03/19
3K0
玩转 PHP 网络编程全套阻塞与非阻塞 IO
上一篇我们撸了不咋样的TCP server,然后还扯了半天的口水,现在呢我们来继续撸客户端
桶哥
2020/05/22
1.4K0
玩转 PHP 网络编程全套阻塞与非阻塞 IO
相关推荐
UDP服务recvfrom函数设置非阻塞
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验