Linux网络IO模型浅析(二)非阻塞IO
非阻塞IO
非阻塞IO与阻塞IO的区别从字面上就可以区分出来,在于调用读写socket的接口函数后,是否发生阻塞。
我们可以通过设置socket为非阻塞模式来进行非阻塞IO的实现。通常有以下两种方法:
- 使用socket提供的接口:
int sock_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
- 使用fnctl直接修改文件属性
int tmp_file_flag = fcntl(sock_fd, F_GETFL, 0);
int now_file_flag = tmp_file_flag | O_NONBLOCK;
fcntl(sock_fd, F_SETFL, now_file_flag);
非阻塞IO读写流程
从上图可看出,当调用read()阻塞函数时,即使kernel并没有将响应准备好,但是并不会block等待可读事件,而是直接返回error。从用户角度看,调用函数后会立刻得到结果,如果有数据则可以读取到并直接进行处理,否则可以自行抉择是继续read轮询还是先处理其他数据。
实际应用中,我们使用recv()进行数据读取,该接口返回值有以下几种情况:
- recv() 返回值大于 返回值大于 0,表示接受数据完毕,返回值即是到的字节;
- recv() 返回 0,表示连接已经正常断开;
- recv() 返回 -1,且errno 等于EAGAIN ,表示recv操作尚未完成;
- recv() 返回 -1,且errno 不等于EAGAIN ,表示recv操作遇到了系统错误;
非阻塞IO的应用场景
在多数情况下,即使设置了socket的文件属性为非阻塞,我们仍然需要不断调用recv接口进行数据获取,实际上消耗与阻塞IO无异。我们应该使用多路复用机制,在单线程情况下高效检测事件是否就绪,如select,epoll等,可以快速检测一个连接是否活跃。
本专栏知识点是通过<零声教育>的系统学习,进行梳理总结写下文章,对c/c++linux课程感兴趣的读者,可以点击链接0voice,查看详细的服务: