【UNIX网络编程】非阻塞式IO总结

前言

这两周又一次忙于项目,不过好在我的考试基本都结束了,所以抓紧速度把UNP这本书全部过了一遍,程序全部编译运行过,重点本分自己手敲了部分代码。现在回来补上自己博客拉下的债了。

1.非阻塞的读和写

这一部分在unp书上的做法实际上时非常复杂的,为了实现非阻塞的IO读写,创立了两个缓冲区, 
1. 用来读取来自客户端上的输入,并输出给服务器的 to 缓冲区, 
2. 用来保存来自服务器返回到客户端上的输入,并输出给终端的 fr 缓冲区 
他们都使用两个指针来维护,一个指向已保存的第一个字节,另一个指向可用的第一个字节。然后使用select轮询 是否有文件描述符可读或者可写,然后使用非阻塞的读写操作。

总结

2.非阻塞的connect

使用非阻塞的connect使用一下步奏: 
1. 使用fcntl将套接字设置为非阻塞fcntl(sockfd, F_SETFL, flags|O_NONBLOCK); 
2. 发起非阻塞的connect,如果返回的错误是EINPROGRESS则忽略该错误。(注意如果connect返回值为0时,那么代表连接 已经立刻建立成功了,可以直接使用)。 
3. 调用select或者poll或者epoll,来等待套接字变成可读或者可写。 
4. 返回后,如果返回值为0则超时,不为0则先调用getsockopt去获取待处理错误 
if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len)<0) 
返回值小于0或者error被设置为不为0的数值,则是有错误。返回值为0那么就代表建立连接成功(建立连接成功或者出错对于select来说都是即可读又可写的)。

3.非阻塞accept

设置非阻塞的accept只需要将监听套接字设置为非阻塞即可,并且由于要将监听套接字设置为非阻塞式的,所以一般为了防止轮询,会使用select或者epoll监视监听套接字,有连接的时候才调用accept,那么这时候问题来了,为什么可读之后还需要使用非阻塞的accept呢? 
原因如下: 
1. 客户在成功连接,完成三次握手之后,设置SO_LINGER选项并且关闭套接字,这时会发送一个RST给服务器 
2. 服务器在select返回之后,由于处理繁忙,未能立刻调用accept,等调用的时候,服务器已经接受到RST,并且这个已完成的连接被清除出队列了,那么accept调用将会阻塞,直到下一个连接到达。

因此使用阻塞式accept就是为了防止这样的情况发生,因此在使用非阻塞式accept的时候需要忽略以下错误:

  • EWOULDBLOCK
  • ECONNABORTED
  • EPROTO
  • EINTR

总结

非阻塞式的读写方式尽量少用,使用epoll监听描述符能解决读写阻塞的问题,非阻塞的connect与accept都可以使用,能提高效率,需要配合select或epoll使用,同时注意要忽略掉必要的错误。

你可能感兴趣的:(【UNIX网络编程】非阻塞式IO总结)