目录
非阻塞式io
一般
我们之前使用过的recv()函数中,有一个flags参数,它可以设置io方式为非阻塞方式
其他函数也有,但每次使用都需要设置,未免有点麻烦,我们有更通用的方法
通用方法 -- fcntl()
介绍
实际上,操作文件时都是使用文件描述符fd
- 每个fd都指向一个文件对象,对象中是有关于文件的属性的,其中就包括flags标志位
如果直接在底层设置了非阻塞方式,所有文件操作都会是非阻塞的
- 比如这里的fcntl,只要设置了就不用管了
- 或是在调用open打开文件时就设置上O_NONBLOCK,原理也是一样的
函数原型
cmd
- cmd值不同,后面追加的可变参数也不同
- (这里说的状态标记就是前面提到的flags)
应用
实现一个将指定文件设置成非阻塞式io的函数:
示例
普通read
#include <iostream> #include <sys/fcntl.h> #include <unistd.h> #include <stdio.h> using namespace std; int main() { cout << "enter:"; fflush(stdout); char buff[100]; int ret = read(0, buff, sizeof(buff) - 1); if (ret > 0) { buff[ret - 1] = 0; cout << "echo: " << buff << endl; } else if (ret == 0) { cout << "end" << endl; } else { cout << "error" << endl; } return 0; }
若我们不主动输入,就会一直阻塞在read函数里
加入fcntl()
#include <iostream> #include <sys/fcntl.h> #include <unistd.h> #include <stdio.h> #include <string.h> #include <errno.h> void set_no_block(int fd) { int ret = fcntl(fd, F_GETFL); if (ret < 0) { perror("fcntl"); return; } fcntl(fd, F_SETFL, ret | O_NONBLOCK); } using namespace std; int main() { cout << "enter:"; fflush(stdout); set_no_block(0); char buff[100]; while (true) { int ret = read(0, buff, sizeof(buff) - 1); if (ret > 0) { buff[ret - 1] = 0; cout << "echo: " << buff << endl; } else if (ret == 0) { cout << "end" << endl; } else { printf("error,errno : %d,strerror: %s\n", errno, strerror(errno)); sleep(1); } } return 0; }
F_GETFL -- 获取标志位
- 返回值返回当前标志位(位图)
F_SETFL -- 设置标志位,一般是新增一个选项
- 要将原标志位和新增选项进行位运算,将位运算的结果填入参数
设置好后,发现在没有数据时,走了返回值<0的情况
- 也正常,毕竟既没有数据可读,也没有读到文件尾
如果打印出错误码和错误信息:
- 错误码是11,表示临时资源不可用
当然,只要我们输入了数据,还是可以正常被上层读走的
那么,设置成非阻塞后,真的出错/没有数据可读都会走else,如何区分?
- 通过错误码errno区分
- 既然没有数据时会被设置为11,那就用这个来区分
- 当然,如果判断语句里直接写11,未免有点挫,EWOULDBLOCK= EAGAIN=11,用这个来代替11
修改后:
#include <iostream> #include <sys/fcntl.h> #include <unistd.h> #include <stdio.h> #include <string.h> #include <errno.h> void set_no_block(int fd) { int ret = fcntl(fd, F_GETFL); if (ret < 0) { perror("fcntl"); return; } fcntl(fd, F_SETFL, ret | O_NONBLOCK); } using namespace std; int main() { cout << "enter:"; fflush(stdout); set_no_block(0); char buff[100]; while (true) { int ret = read(0, buff, sizeof(buff) - 1); if (ret > 0) { buff[ret - 1] = 0; cout << "echo: " << buff << endl; } else if (ret == 0) { cout << "end" << endl; } else { // printf("error,errno : %d,strerror: %s\n", errno, strerror(errno)); if (errno == EWOULDBLOCK) { cout << "no data,try again" << endl; //如果没有就绪,我们可以在判断成功后做其他事情 } else { cout << "read error" << endl; } sleep(1); } } return 0; }