目录
用户进程空间<-->内核空间
内核空间<-->设备空间(磁盘、网卡等)
线程在运行过程中,可能由于以下几种原因进入阻塞状态:
可能阻塞套接字的Linux Sockets API调用分为以下四种

内核也有数据缓存区,数据好了再拷贝到应用的缓存区中,包括read,accept、connect等


示例
read
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- #define FIFO_NAME "/tmp/myfifo"
-
- int main(int argc, char *argv[]) {
- int fd, ret;
- char buf[BUFSIZ] = {};
-
- // 创建有名管道
- if (mkfifo(FIFO_NAME, 0666) == -1) {
- perror("mkfifo");
- exit(0);
- }
-
- fd = open(FIFO_NAME, O_RDONLY|O_NONBLOCK); //非阻塞方式NONBLOCK
- if(fd < 0) {
- perror("open");
- exit(0);
- }
-
- while(1) {
- // do {
- ret = read(fd, buf, BUFSIZ);
- // } while (ret < 0 && errno == EAGAIN); //如果读失败了,并且原因是EAGAIN才会反复轮询读
- // if(ret < 0){ //如果满足EGAIN但是,但是RET<0,是其他异常情况
- // perror("read");
- // exit(0);
- // }
- if(buf[0] == '#')
- break;
- printf("Read from pipe: %s\n", buf);
- }
-
- // 关闭管道并删除有名管道文件
- close(fd);
- unlink(FIFO_NAME);
-
- return 0;
- }
该程序通过使用read函数从文件描述符fd中读取数据,存储在buf中。BUFSIZ是一个常量,表示可以读取的最大字节数。当读取成功时,read函数返回实际读取的字节数,如果返回值小于0,则表示读取出现错误。
程序使用循环来反复读取数据,直到遇到以#开头的字符串,才会跳出循环。在读取过程中,如果读取失败了,并且原因是EAGAIN,则会一直轮询读取,直到成功读取为止。
注释掉的部分是对异常情况的处理,如果出现其他异常情况,则会输出错误信息并退出程序。
write函数仅用来测试,无特别说明
- #include
- #include
- #include
- #include
- #include
- #include
-
- #define FIFO_NAME "/tmp/myfifo"
-
- int main(void) {
- int fd;
- char buf[BUFSIZ];
-
- // 打开有名管道并进行读写操作
- fd = open(FIFO_NAME, O_WRONLY);
- if( fd < 0 ) {
- perror("open");
- exit(0);
- }
- while(1) {
- fgets(buf, BUFSIZ, stdin);
- if (write(fd, buf, BUFSIZ) < 0 ) {
- perror("write");
- exit(0);
- }
- if(buf[0] == '#')
- break;
- }
-
- close(fd);
- return 0;
- }
与read区别,可以监听多个文件描述符,有的可能有数据,有的可能没有数据。
如果有数据准备好的描述符,返回可读条件,如哪个文件描述符好了。
如果有数据了,调用recvfrom拷贝数据报,再进行处理。如果有多个文件描述符就执行多个这样的过程。
2.4 信号驱动式I/O注册完就可以干别的事情了,类似异步操作。

上面4种,在数据报准备好之后拷贝数据的时候都是阻塞的,都算作是同步IO,都需要recv读一下。

内核无数据到数据报拷贝完成,这两部都是非阻塞的,应用程序干干什么就干什么。

画出5种I/O模型调用过程