阻塞式io
一个简单的用户输入回显功能,在用户未输入内容时,会一直阻塞住
#include <iostream>
#include <unistd.h>using namespace std;
int main()
{char buff[1024];while (true){cout << "please enter@ ";fflush(stdout);ssize_t n = read(0, buff, sizeof(buff));if (n > 0){buff[n - 1] = 0;cout << "echo:" << buff << endl;}else if (n == 0){cout << "read finish" << endl;break;}else if (n < 0){cout << "read error" << endl;break;}}return 0;
}
fctnl
一个文件描述符,默认都是阻塞io
函数原型如下:
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, … /* arg */ );
传入的cmd值不同,后面追加的参数也不相同
fctnl函数有5种功能:
- 复制一个现有的描述符 (cmd=F_DEPFD)
- 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD)
- 获得/设置文件状态标记(cmd=F_GETFL或F_SETFL)
- 获得/设置异步io所有权(cmd=F_GETOWN或F_SETOWN)
- 获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW)
此处用第三种功能,设置文件状态标记,就可以将一个文件描述符设置为非阻塞
实现非阻塞
实现函数SetNoBlock,基于fcntl,实现这个函数,将文件描述符设置为非阻塞
void SetNoBlock(int fd)
{int f1 = fcntl(fd, F_GETFL);if (f1 < 0){perror("fctnl");return;}fcntl(fd, F_SETFL, f1 | O_NONBLOCK);cout << " set " << fd << " nonblock done" << endl;
}
使用F_GETFL将当前的文件描述符的属性取出来(这是一个位图)
然后再使用F_SETFL将文件描述符设置回去,设置回去的同时,加上一个O_NONBLOCK参数
read会立即返回,当n<0时不break,打印read返回值和描述,轮询方式查看read状态
cerr << “read error,” << “error str:” << errno << “,” << strerror(errno) << endl;
没就绪时会以出错的方式返回,那怎么区分是真的出错了还是没有就绪,可以通过上面的错误码11判断,也就是宏EWOULDBLOCK
// 非阻塞,底层没有就绪,recv/read/write/send,返回值出错返回// 怎么区分 a.真的出错 b.底层没有就绪,通过errnoif (errno == EWOULDBLOCK){cout << "fd not ready, try again" << endl;// do other thing;}else{cerr << "read error," << "error str:" << errno << "," << strerror(errno) << endl;sleep(1);}