UNIX网络编程笔记(6):I/O复用之select函数
来源:互联网 发布:社交网络 720p mkv 编辑:程序博客网 时间:2024/06/05 11:12
上一讲中我们正确处理了僵尸子进程,使得这个简单的服务器更加健壮。不幸的是,这个程序仍然有问题。想象一下,如果一个客户正在和一个服务器子进程连接建立完毕正在通话,而服务器子进程意外终止(比如kill),服务器TCP向客户TCP发送一个FIN,但客户端正在调用fgets函数等待用户输入字符而得不到这个FIN,直到套接字读为止(可能过了很长时间)。
1、来看看问题是什么
首先启动服务器与客户,建立连接:
客户输入nihao后服务器正确回射,然后kill掉服务器子进程后客户输入and...,输出错误:
服务器端重启(上一讲中解决的问题)。
这个过程发生了什么?
(1)当kill掉服务器子进程后,服务器父进程正确处理了SIGCHLD信号。服务器也向客户发送一个FIN,客户回应一个ACK,TCP连接终止的前半部分完成;
(2)客户上没有发生任何特殊的事,客户TCP接收到服务器的FIN后回应一个ACK,但问题是客户正阻塞在fgets上,等待用户输入;
(3)在客户上再输入and...,导致错误发生:str_cli调用write,客户TCP接着把数据发送给服务器,但是客户FIN的接收并没有告知客户TCP服务器进程已经终止。当服务器TCP接收到客户的数据时,发送一个RST;
(4)但是客户进程看不到这个RST,因为调用write后直接调用readline,并且由于之前接收的FIN,导致readline直接返回0(表示EOF)。但客户没有预期收到EOF,于是出错;
(5)客户终止,所有打开的描述符关闭;
问题的根本在于,当FIN到达套接字时,客户正阻塞在fgets调用上。客户实际上在应对两个描述符:套接字和用户输入,它不能单纯阻塞在某个特定的源上。select函数可以解决这个问题。
2、select函数
有些进程需要一种预先告知内核的能力,使得内核一旦发现进程指定的一个或多个I/O条件就绪时,它就通知进程。这个能力就是I/O复用。
select函数允许进程指示内核等待多个事件中的任何一个发生,并只在有一个或多个事件发生或经历一段指定的时间后才唤醒它。
下面的例子指出select可以告知内核在什么条件下发生时返回:
- 集合{1,4,5}中的任何描述符准备好读;
- 集合{2,7}中的任何描述符准备好写;
- 集合{1,4}中的任何描述符由异常条件待处理;
- 已经过了12.8秒;
#include <sys/select.h>#include <sys/time.h>int select(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set * exceptset,const struct timeval *timeout);函数如果有描述符就绪就返回数量,超时返回0,出错返回-1。
void str_cli(FILE *fp,int sockfd){int maxfdp1;fd_set rset;char sendline[MAXLINE],recvline[MAXLINE];FD_ZERO(&rset);int n;for(;;){FD_SET(fileno(fp),&rset);FD_SET(sockfd,&rset);maxfdp1=max(fileno(fp),sockfd)+1;if((n=select(maxfdp1,&rset,NULL,NULL,NULL))==0){printf("select timeout\n");return;}else if(n<0){printf("select error\n");return;}if(FD_ISSET(sockfd,&rset)){if(readline(sockfd,recvline,MAXLINE)==0){printf("str_cli:server terminated prematurely\n");return;}fputs(recvline,stdout);}if(FD_ISSET(fileno(fp),&rset)){if(fgets(sendline,MAXLINE,fp)==NULL)return;write(sockfd,sendline,strlen(sendline));}}}函数首先检查套接字,如果套接字是可读的,那么就用readline读入回射文本并输出;如果标准输入是可读的,就调用fgets读入一行,然后写入套接字。
- UNIX网络编程笔记(6):I/O复用之select函数
- Unix网络编程学习笔记之第6章 I/O复用:select和poll函数
- Unix网络编程(六)高级I/O技术之复用技术 select
- Unix网络编程—— I/O复用之select
- Unix网络编程(六)高级I/O技术之复用技术 select
- Unix Socket编程--I/O复用之select模型
- Unix Socket编程--I/O复用之select模型
- Unix Socket编程--I/O复用之select模型
- 【unix网络编程第三版】阅读笔记(五):I/O复用:select和poll函数
- 《UNIX网络编程 卷1》 笔记: I/O复用 select函数
- Unix网络编程代码 第6章 I/O复用:select、poll和epoll函数
- Linux网络编程---I/O复用模型之select
- 网络编程之I/O复用模型select
- 《UNIX网络编程 卷1》 笔记: 高级I/O函数
- Unix系统编程(6) - I/O多路复用之select
- 【Unix 网络编程】服务器网络编程模型——I/O复用:select 函数
- UNIX网络编程:I/O复用技术(select、poll、epoll)
- UNIX网络编程:I/O复用技术(select、poll、epoll)
- Linux终端的颜色码
- SYSPROCESSES 查看连接
- openjudge 集合加法
- 互联网之殇
- HTML笔记(基本标签)
- UNIX网络编程笔记(6):I/O复用之select函数
- C语言命名
- Android
- 解决This function or variable may be unsafe的方法
- light--oj--1294-- Positive Negative Sign(数学规律)
- 工作小记(五)----完工归来
- Ubuntu更新数据源
- php-redis扩展编译
- qt+opencv3.0配置详解