进程需要一种预先告知内核的能力,使得内核一旦发现进程指定的一个或多个I/O条件就绪(也就是说输入 已准备好被读取,或者描述字已经能承受更多的输出),它就通知进程。这个能力称谓I/O复用,是由select和poll这两个函数支持的。
I/O复用典型使用在下列 网络应用场合:
1.当客户处理多个描述字时(通常是交互式输入和网络套接口),必须使用I/O复用。
2.一个客户同时处理多个套接口是可能的,不过比较少见。
3.如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般就要使用I/O复用。
4.如果一个服务器既要处理TCP又要处理UDP,一般就要使用I/O复用。
5.如果一个服务器要处理多个服务或者多个协议,一般要使用I/O复用。
I/O复用并非只限于网络 编程,许多正式应用程序也需要使用这项技术。
I/O模型:
阻塞
非阻塞
进程把套接口设置成非阻塞是在通知内核:当所请求的I/O操作非得把本进程投入睡眠才能完成时,不要把本 进程投入睡眼,而是返回一个错误。
I/O复用
信号驱动I/O(SIGIO)
异步I/O(POSIX的aio_系统函数)
Timeval结构用于指 定这段时间的秒数和微秒数:
Struct timeval{
Long tv_sec;
Long tv_usec;
};
这个参数有三种可能:
1.永远等待下去:仅在有一个描述字准备好I/O时才返回。为此我们把参数设置为空指针。
2.等待一段固定时间:在有一个描述字准备好I/O返回,但是不超过由该参数指向的timeval结构中指定的秒数和微秒数。
3.根本不等待:检查描述字后立即返回,这称为轮询。为此,定时器值为0.
使用select时最常见的两个编程错误是:忘了最大描述字加1;忘描述字集是值-结果参数。
Select函数的返回值 表示跨所有描述字集的已就绪的总位数。
1.下列四个条件中任何一个满足时,一个套接口准备好读:
A.该套接口接收缓冲区的数据字节数大于等于套接口接收缓冲区低潮标记的当前大小。
B.该连接的读这一半关闭(也就是接收了FIN的TCP连接)。对这样的套接口读操作将不阻塞并返回0。
C.该套接口是一个监听套接口且已经完成的连接数不为0。对这样的套接口的accept通常不会阻塞。
D.其上有一个套接口错误等待处理。
2.下列四个条件中任何一个满足时,一个套接口准备好写:
A.该套接口发送缓冲区的 数据字节数大于等于套接口发送缓冲区低潮标记的当前大小。
B.该连接的写这一半关 闭。对这样的套接口写操作产生SIGPIPE信号。
C.套接口早先是使用非阻 塞connect以建立连 接,并且连接已经异步建立,或者connect已经以失败告终。
D.其上有一个套接口错误 等待处理。
注意:当某个套接口上发生错误时,它将由select标记为既可读也可写。
接收和发送低潮标记的目标在于:允许应用进程控制在select返回可读或可写条件之前,有多少数据可读 或有多大空间可写。
任何UDP套接口只要其发送低潮标记小于等于发送缓冲区大小(缺省应该总是这种关系)就总是可 写的,这是因为UDP套接口 不需要连接。
1.close把描述字的引用计数减1,仅在该计数变为0时才关闭套接口。
2.Close终止数据传送的两个方向,读和写。
Shutdown关闭一半 的TCP连接。
使用select和shutdown,其中前者在服务器旦关闭它那一端的连接时通知我们,后者允许我们正确地处理批量输入。
解决拒绝服务攻击:
1.使用非阻塞I/O
2.每个客户由单独的控制线程提供服务
3.对I/O操作设置一个超时