http://blog.csdn.net/ly21st http://ly21st.blog.chinaunix.net
分类: LINUX
2011-09-18 15:49:32
I/O复用典型地用在下列网络应用场合:
1)当客户处理多个描述字时,必须使用I/O复用;
2)一个客户同时处理多个套接口是可能的,但很少出现;
3)如果一个tcp服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用;
4)如果一个服务器既要处理tcp,又要处理udp,一般也要使用I/O复用;
5)如果一个服务器要处理多个服务或多个协议,一般要使用I/O复用。
6.2 unix下五个I/O模型1)阻塞I/O;
2)非阻塞I/O;
3)I/O复用;
4)信号驱动I/O(SIGIO);
5)异步I/(Posix.1的aio_系列函数)
一个输入操作一般有两个不同的阶段:
1)等待数据准备好;
2)从内核到进程拷贝数据。
对于一个套接口上的输入操作,第一步一般是等待数据到达网络,当分组到达时,它被拷贝到内核中的某个缓冲区,第二步是将数据从缓冲区拷贝到应用程序缓冲区。
信号驱动I/O模型的好处是当等待数据报到达时,可以不阻塞。主循环可以继续执行,只是等待信号处理程序的通知:或者数据已准备好处理,或者数据报已准备好被读。
6.3 select函数
select函数中间的三个参数指定我们要让内核测试读、写和异常条件所需的描述字。现在只支持两个异常条件:
1) 套接口带外数据的到达;
2) 控制状态信息的存在,可从一个已置为分组方式的伪终端主端读到。
下列四个条件中的任何一个满足时,套接口准备好读:
a. 套接口接收缓冲区中的数据字节数大于等于套接口接收缓冲区低潮限度的当前值。对这样的套接口的读操作将并不阻塞并返回一个大于0的值(即准备好读入的数据量)。我们可以用套接口选项SO_RCVLOWAT来设置此低限度,对于tcp和udp套接口,其缺省值为1。
b.,连接的读这一半关闭(也就是说接收了FIN 的tcp连接)。对这样的套接口的读操作将不阻塞并且返回0(即文件结束符)。
c. 套接口是一个监听套接口且已完成的连接数为非0.
d.有一个套接口错误待处理。对这样的套接口的读操作将不阻塞且返回一个错误(-1),errno则设置成明确的错误条件。这些待处理的错误也可通过指定套接口选项SO_ERROR调用getsockopt来取得并清除.
下列三个条件中的任何一个满足时,套接口准备好写:
a. 套接口发送缓冲区中的可用空间字节数大于等于套接口发送缓冲区低潮限度的当前值,我们可以用套接口选项SO_SNDLOWAT来设置此低潮限度,对于tcp和udp套接口,其缺省值一般是2048.
b. 连接的写这一半关闭。对这样的套接口的写操作将产生信号SIGPIPE。
c. 有一个套接口错误待处理。
如果一个套接口存在带外数据或者仍处于带外数据,那它有异常条件待处理。
注意:当一个套接口出错时,它由select标记为既可读又可写。
#include "unp.h"
void
str_cli(FILE *fp, int sockfd)
{
int maxfdp1;
fd_set rset;
char sendline[MAXLINE], recvline[MAXLINE];
FD_ZERO(&rset);
for ( ; ; ) {
FD_SET(fileno(fp), &rset);
FD_SET(sockfd, &rset);
maxfdp1 = max(fileno(fp), sockfd) + 1;
Select(maxfdp1, &rset, NULL, NULL, NULL);
if (FD_ISSET(sockfd, &rset)) { /* socket is readable */
if (Readline(sockfd, recvline, MAXLINE) == 0)
err_quit("str_cli: server terminated prematurely");
Fputs(recvline, stdout);
}
if (FD_ISSET(fileno(fp), &rset)) { /* input is readable */
if (Fgets(sendline, MAXLINE, fp) == NULL)
return; /* all done */
Writen(sockfd, sendline, strlen(sendline));
}
}
}
6.8 TCP回射服务器程序(修订版)
拒绝服务型攻击的可能解决方法:
a.使用费阻塞I/O模型;
b.让每个客户由单独的控制线程提供服务;
c.对I/O操作设置超时。
注意:
1) tcp的带外数据被认为是优先级带数据;
2) 当tcp连接的读这一半关闭时(例如,接收了一个FIN),这也认为是普通数据,且后续的读操作将返回0;
3) tcp连接存在错误既可以认为是普通数据,也可以认为是错误(POLLERR)。无论是哪种情况,后续的读操作都将返回-1,并将errno置为适当的值,这就处理了诸如接收到RST或超时等条件。
4) 在监听套接口上新连接的可用性既可认为是普通数据,也可认为是优先级数据,大多数实现都将其作为普通数据来考虑。