chapter6
- 6.1 概述
- I/O复用典型使用在下列网络应用场合。
- (1):当客户处理多个描述符时,必须使用IO复用
- (2):一个客户同时处理多个套接字是可能的,不过不叫少见。
- (3):如果一个TCP服务器既要处理监听套接字,又要处理已连接套接字。
- (4):如果一个服务器既要处理TCP,又要处理UDP
- (5):如果一个服务器要处理多个服务或多个协议
- IO复用并非只限于网络,许多重要的应用程序也需要使用这项技术。
- 6.2 I/O模型
- 在Unix下可用的5种I/O模型的基本区别:
- (1)阻塞式I/O
- (2)非阻塞式I/O
- (3)I/O复用(select和poll)
- (4)信号驱动式I/O(SIGIO)
- (5)异步I/O(POSIX的aio_系列函数)
- 6.2.1 阻塞式I/O
- 6.2.2 非阻塞式I/O模型
- 6.2.3 I/O复用模型
- 有个I/O复用,我们就可以调用select或poll,阻塞在这两个系统调用中的某一个之上,而不是阻塞在真正的I/O系统调用上。
- 6.2.4 信号驱动式I/O模型
- 我们也可以用信号,让内核在描述符就绪时发送SIGIO信号通知我们。我们称这种模型为信号驱动式I/O
- 6.2.5 异步I/O模型
- 6.3 select函数
- 该函数允许进程指示内核等待多个事件中的任何一个发生,并且在有一个或多个事件发生或经历一段指定的时间后才唤醒它。
- 我们调用select告知内核对那些描述符(就读写或异常)感兴趣以及等待多长时间。
- #include <sys/select.h>
- #include <sys/time.h>
- int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, cosnt struct timeval *timeout);
- maxfdp1:最大的描述符ID+1
- struct timeval
- {
- long tv_sec; //秒
- long tv_usec;//微妙
- };
- void FD_ZERO(fd_set *fdset);
- void FD_SET(int fd, fd_set *fdset);
- void FD_CLR(int fd, fd_set *fdset);
- int FD_ISSET(int fd, fd_set *fdset);
- 6.3.1描述符就绪条件
- (1):满足下列4个条件中的任何一个时,一个套接字准备好读
- a):
- ......
- (1):满足下列4个条件中的任何一个时,一个套接字准备好读
- 6.3.2 select的最大描述符
- 6.4 str_cli函数
- 6.5 批量输入
- 6.6 shutdown函数
- 终止网络连接的方法不是调用close函数。不过close有两个限制,却可以使用shutdown来避免
- (1):close把描述符的引用计数减1,但在该计数为0时才关闭套接字
- (2):close终止读和写两个方向的数据传送。
- #include <sys/socket.h>
- int shutdown(int sockfd, int howto);
- OK : 0 FAILED:-1
- 6.8 TCP Service
-
1 /* include fig01 */ 2 #include "unp.h" 3 4 int 5 main(int argc, char **argv) 6 { 7 int i, maxi, maxfd, listenfd, connfd, sockfd; 8 int nready, client[FD_SETSIZE]; 9 ssize_t n; 10 fd_set rset, allset; 11 char buf[MAXLINE]; 12 socklen_t clilen; 13 struct sockaddr_in cliaddr, servaddr; 14 15 listenfd = Socket(AF_INET, SOCK_STREAM, 0); 16 17 bzero(&servaddr, sizeof(servaddr)); 18 servaddr.sin_family = AF_INET; 19 servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 20 servaddr.sin_port = htons(SERV_PORT); 21 22 Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); 23 24 Listen(listenfd, LISTENQ); 25 26 maxfd = listenfd; /* initialize */ 27 maxi = -1; /* index into client[] array */ 28 for (i = 0; i < FD_SETSIZE; i++) 29 client[i] = -1; /* -1 indicates available entry */ 30 FD_ZERO(&allset); 31 FD_SET(listenfd, &allset); 32 /* end fig01 */ 33 34 /* include fig02 */ 35 for ( ; ; ) { 36 rset = allset; /* structure assignment */ 37 nready = Select(maxfd+1, &rset, NULL, NULL, NULL); 38 39 if (FD_ISSET(listenfd, &rset)) { /* new client connection */ 40 clilen = sizeof(cliaddr); 41 connfd = Accept(listenfd, (SA *) &cliaddr, &clilen); 42 #ifdef NOTDEF 43 printf("new client: %s, port %d ", 44 Inet_ntop(AF_INET, &cliaddr.sin_addr, 4, NULL), 45 ntohs(cliaddr.sin_port)); 46 #endif 47 48 for (i = 0; i < FD_SETSIZE; i++) 49 if (client[i] < 0) { 50 client[i] = connfd; /* save descriptor */ 51 break; 52 } 53 if (i == FD_SETSIZE) 54 err_quit("too many clients"); 55 56 FD_SET(connfd, &allset); /* add new descriptor to set */ 57 if (connfd > maxfd) 58 maxfd = connfd; /* for select */ 59 if (i > maxi) 60 maxi = i; /* max index in client[] array */ 61 62 if (--nready <= 0) 63 continue; /* no more readable descriptors */ 64 } 65 66 for (i = 0; i <= maxi; i++) { /* check all clients for data */ 67 if ( (sockfd = client[i]) < 0) 68 continue; 69 if (FD_ISSET(sockfd, &rset)) { 70 if ( (n = Read(sockfd, buf, MAXLINE)) == 0) { 71 /*4connection closed by client */ 72 Close(sockfd); 73 FD_CLR(sockfd, &allset); 74 client[i] = -1; 75 } else 76 Writen(sockfd, buf, n); 77 78 if (--nready <= 0) 79 break; /* no more readable descriptors */ 80 } 81 } 82 } 83 } 84 /* end fig02 */
-
- 6.9 pselect函数
- #include <sys/select.h>
- #include <signal.h>
- #include <time.h>
- int pselect(int masfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,const struct timespec *timeout,const sigset_t *sigmask);
- pselect相对于通常的select有两个变化
- pselect使用timespec结构,而不使用timeval结构。
- struct timespec{
- time_t tv_sec;
- long tv_nsec; // 纳秒书
- };
- struct timespec{
- pselect函数增加了第六个参数:一个指向信号掩码的指针。
- ......
- pselect使用timespec结构,而不使用timeval结构。
- 6.10 poll函数
- #include <poll.h>
- int poll(struct pollfd *fdarray,unsigned long nfds, int timeout);
- 如果有就绪描述符则返回去数目,若超时则为0,若出错则为-1
- struct pollfd{
- int fd;
- short events;
- short revents;
- };