将网络描述符设置为非阻塞的场景

很多服务器项目的实现中都有一句set_non_block(acceptfd),为什么要将acceptfd设为非阻塞?

仔细想想,服务器使用socket_bind_listen三件套进行监听并将listenfd注册到epoll监控后,当有新的连接请求来临,会先通过内核协议栈完成TCP三次握手,这些完成三次握手的连接信息被维护在一个队列中(因为暂时还未被应用程序accept),此时epoll会感知到listenfd的可读事件并待应用程序调用accept返回这个连接的描述符。但是有一些特殊的情况如调用socket的close函数并且置l_onoff = 1, l_linger =0,这种情况是为了尽快回收套接字资源,不发送FIN报文而发送RST报文,套接字直接进入CLOSE状态,不会进入TIMEWAIT状态.这种情况就要求非阻塞accept的存在.

举例,当客户度端发起连接,完成了三次握手之后,此时服务器端因为很忙碌,还没有调用accept函数来确认这个连接。此时客户端使用close函数关闭了连接,注意此时客户端发送的是RST报文而不是FIN报文,所以该链接就在内核中就被断开了,但是此时应用层并不知道这种变化,如果此时服务器端经过epoll触发的listenfd调用阻塞的accept,由于连接已经被取消,所以accept就会被阻塞在一个已经无效的套接字上,那么其他注册在epoll中的fd就不能被及时处理,所以我们需要将listenfd设置为非阻塞,当设置accept是非阻塞的时,如果有连接存在,那么accept正常返回.如果时没有连接存在,或者像上述所说的连接被取消了,那么会返回不同的错误码,我们只需要在accept返回错误后检查这些错误码即可知道发生了什么。

 

ps:尝试了如果在accept之前,客户端使用正常的close,也就是发送FIN报文的话,服务器accept会成功返回正常的acceptfd,只不过依然会触发读事件,且读事件处理时会读到0。也就是说正常的退出不会出现上述情况,非阻塞的accept主要是针对之前分析的某一端想提前拆链而主动发送RST报文的场景。

 

参考:https://blog.csdn.net/yushiyaogg/article/details/38322701?utm_source=blogxgwz1

         https://www.cnblogs.com/JohnABC/p/6323046.html

posted @ 2020-04-28 19:12  Joker1937  阅读(309)  评论(0编辑  收藏  举报