UNP第十六章 非阻塞式I/O
来源:互联网 发布:沃尔玛数据流程图 编辑:程序博客网 时间:2024/05/17 13:09
概述
套接字的默认状态是阻塞的,可能被阻塞的套接字调用分为以下四类:
- 输入操作:包括read、readv、recv、recvfrom和recvmsg共5个函数。(1)如果某个进程对一个阻塞的TCP套接字调用这些输入函数之一,而且该套接字的接受缓冲区中没有数据可读,该进程将被投入睡眠,直到有一些数据到达。(2)对于非阻塞的套接字,如果输入操作不能被满足,相应调用将立即返回一个EWOULDBLOCK错误。
- 输出操作:包括write、writev、send、sendto和sendmsg共5个函数。(1)对于阻塞套接字,如果其发送缓冲区中没有空间,进程将被投入睡眠,直到有空间为止。(2)对于一个非阻塞的TCP套接字,如果其发送缓冲区中根本没有空间,返回将是内核能够复制到该缓冲区中的字节数。
- 接受外来连接:例如connfd = Accept();(1)如果迟迟没有客户端请求连入,则服务器进程将投入睡眠。(2)如果对一个非阻塞的套接字调用accept函数,并且尚无新的连接到达,accept调用将立即返回一个EWOULDBLOCK错误。
- 发起外出连接:即用于TCP的connect函数
非阻塞式I/O与阻塞式I/O的比喻
- 阻塞式I/O:假设我要到菜鸟驿站(取快递的地方就是内核缓冲区)去快递,但是我不知道快递什么时候过来,这时候我只能死等着(睡眠),直到菜鸟驿站给我发送短信通知,我才被唤醒,然后去取快递。
- 非阻塞式I/O:假设我要到菜鸟驿站取快递,这次我采取每20分钟去菜鸟驿站看快递到了没:如果快递没到,我就立即回寝室(返回EWOULDBLOCK);如果在每20分钟的轮询中查到快递已到达,那么我就去菜鸟驿站(内核缓冲区)取快递。
非阻塞读和写:str_cli函数
在以往的基础上添加两个缓冲区:to和from。
to缓冲区中包含从标准输入读取的空间、要发往服务器的数据(正在排队)和已发送成功的数据。
from缓冲区中包含从TCP套接字读取的空间,要发往标准输出的数据(正在排队)和已发送成功的数据。
操作to和from的主要代码如下:
//缓冲区的创建以及初始化char to[MAXLINE], fr[MAXLINE];char *toiptr, *tooptr, *friptr, *froptr;toiptr = tooptr = to;friptr = froptr = fr; //如果文件未结束且to缓冲区中尚有可从标准输入读入的空闲空间if (stdineof == 0 && toiptr < &to[MAXLINE]) FD_SET(STDIN_FILENO, &rset);//设置Select轮询描述符状态 Select(maxfdp1, &rset, &wset, NULL, NULL);//完成从标准输入读入缓冲区的操作if (FD_ISSET(STDIN_FILENO, &rset)) {//如果标准输入准备好 //从标准输入读入检查 if((n = read(STDIN_FILENO, toiptr, &to[MAXLINE] - toiptr)) < 0) { if(errno != EWOULDBLOCK) err_sys("read error on stdin"); } else if (n == 0) { fprintf(stderr, "%s:EOF on stdin\n", gf_time()); stdineof = 1; //设置读入结束标志 if (tooptr == toiptr)//要发往服务器数据空间为0,则发送操作完成 Shutdown(sockfd, SHUT_WR); //置TCP为半关闭,传输后续未完成数据 } else { fprintf(stderr, "%s:read %d bytes from stdin\n", gf_time(), n); toiptr += n; //读入成功,移动指针,使得要发往服务器数据空间增加:增加一组排队发往服务器的数据 FD_SET(sockfd, &wset);}}
总结:使用非阻塞I/O使程序能够发挥动态性的优势,只要I/O操作有可能发生,就执行合适的读操作或写操作。通过Select函数,我们可以让内核告知我们何时某个I/O操作可以发生。
str_cli的简单版本
利用fork把当前进程划分为一个父进程和一个子进程。子进程把来自服务器的文本行复制到标准输出,父进程把来自标准输入的文本行复制到服务器,如图。
代码如下,从中可以看到如何在一个函数中分别操纵父子进程。
#include "unp.h"void str_cli1(FILE *fp, int sockfd){ pid_t pid; char sendline[MAXLINE], recvline[MAXLINE]; if( (pid = Fork()) == 0) {//if包裹范围内为子进程 while(Readline(sockfd, recvline, MAXLINE) > 0) Fputs(recvline, stdout); kill(getppid(), SIGTERM); } while (Fgets(sendline, MAXLINE, stdin) != NULL) Writen(sockfd, sendline, strlen(sendline)); Shutdown(sockfd, SHUT_WR); pause(); return;}
非阻塞connect
阅读全文
0 0
- UNP第十六章 非阻塞式I/O
- UNP学习笔记(第十六章 非阻塞I/O)
- 第十六章 非阻塞I/O
- UNP函数笔记十三: 非阻塞式I/O
- UNP总结 Chapter 15~17 Unix域协议、非阻塞式I/O、ioctl操作
- UNIX网络编程卷一:第十六章 非阻塞I/O
- 非阻塞I/O
- 非阻塞I/O
- 非阻塞I/O
- 第16章 非阻塞式I/O
- 第11章非阻塞I/O
- 非阻塞文件I/O
- 非阻塞I/O简介
- 非阻塞I/O笔记
- 非阻塞I/O简介
- 83-非阻塞 I/O
- 阻塞与非阻塞I/O
- 阻塞与非阻塞I/O
- Pytorch是什么?关于Pytorch
- 关于转发、重定向、表单提交、超链接跳转路径分析
- idea常用技巧收集
- 常见的网络协议
- Spring MVC前奏
- UNP第十六章 非阻塞式I/O
- A
- 动态规划经典题讲解
- CAD编辑指南1:CAD图纸的批量打印和批量修改文字
- POJ
- 编程珠玑课后题答案-3.5
- CODEVS 1286(伸展树)
- linux文本管理工具命令详解
- PDF编辑指南1:PDF水印的删除和添加