UNP学习第六章(二)
一、描述符就绪条件
对于引起select返回套接字“就绪”的条件我们必须讨论得更明确:
(1)满足一下塞个条件中的仍和一个时,一个套接字准备好读。
a)该套接字接收缓冲区中的数据字节数不大于等于套接字接收缓冲区低水位标记的当前大小。相关SO_RCVLOWAT默认值为1
b)该连接的读半部关闭(也就接收了FIN的TCP连接)。对这样的套接字读操作将不阻塞并返回0(返回EOF)
c)该套接字是一个监听套接字且已完成的连接数不为0(accept不阻塞)
d)其上有一个套接字错误待处理。
(2)下列四个条件中任何一个满足时,一个套接字准备好写。
a)该套接字发送发送缓冲区中的可用空间字节数大于等于套接字发送缓冲区低水位标记的当前大小,
并且该套接字已连接,或者该套接字不需要连接。相关SO_SNDLOWAT默认2048
b)该链接写半部关闭。写操作将产生SIGPIPE
c)使用非阻塞式connect套接字已建立连接,或者connect已经以失败告终
d)其上有一个套接字错误待处理。
(3)如果一个套接字存在带外数据或者仍处于带外标记,那么它有异常条件待处理。
二、shutdown函数
#include <sys/socket.h> int shutdown(int sockfd, int howto); 返回:成功为0,出错-1 sockfd:套接字描述符 howto: SHUT_RD:关闭连接的读这一半,套接字不再有数据可接收 SHUT_WR:关闭连接的写这一半,套接字不再有数据可发送 SHUT_RDWR:连接的读半部和写半部都关闭
str_cli函数(再修订版):
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include "unp.h" 2 3 void 4 str_cli(FILE *fp, int sockfd) 5 { 6 int maxfdp1, stdineof; 7 fd_set rset; 8 char buf[MAXLINE]; 9 int n; 10 11 stdineof = 0; 12 FD_ZERO(&rset); 13 for( ; ;) { 14 if(stdineof == 0) 15 FD_SET(fileno(fp), &rset); 16 FD_SET(sockfd, &rset); 17 maxfdp1 = max(fileno(fp), sockfd) + 1; 18 Select(maxfdp1, &rset, NULL, NULL, NULL); 19 if(FD_ISSET(sockfd, &rset)) { 20 if((n = Read(sockfd, buf, MAXLINE)) == 0) { 21 if(stdineof == 1) 22 return; 23 else 24 err_quit("str_cli: server terminated prematurely"); 25 } 26 Write(fileno(stdout), buf, n); 27 } 28 if(FD_ISSET(fileno(fp), &rset)) { 29 if((n = Read(fileno(fp), buf, MAXLINE)) == 0) { 30 stdineof = 1; 31 Shutdown(sockfd, SHUT_WR); 32 FD_CLR(fileno(fp), &rset); 33 continue; 34 } 35 Writen(sockfd, buf, n); 36 } 37 } 38 }
三、pselect函数
#include <sys/select.h> #include <signal.h> #include <time.h> int pselect(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timespec *timeout, const sigset_t *sigmask);
返回:若有就绪描述符则为其数目,若超时则为0,若出错则为-1
maxfdp1:最大描述符集+1
readset:读集
writeset:写集
exceptset:异常集
timeout:延时
sigmask:掩码
pselect()用来等待文件描述词状态的改变,和select()类似,它增加了超时值的精度,并且可以在等待文件描述符“准备好”的同时指定一组信号掩码。
四、poll函数
#include <poll.h> int poll(struct pollfd *fdarray, unsigned long nfds, int timeout); 返回:若有就绪描述符则为其数目,若超时则为0,若出错则为-1
struct pollfd {
int fd;
short events;
short revents;
}
fdarray:指向结构数组第一个元素的指针 nfds:用于标记数组fds中的结构体元素的总数量 timeout:是poll函数调用阻塞的时间,单位:毫秒
poll的百度示例,和select类似
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <time.h> 4 #include <string.h> 5 #include <errno.h> 6 #include <poll.h> 7 #include <fcntl.h> 8 #include <unistd.h> 9 10 #define MAX_BUFFER_SIZE 1024 11 #define IN_FILES 3 12 #define TIME_DELAY 60*5 13 #define MAX(a,b) ((a>b)?(a):(b)) 14 15 int 16 main(int argc, char **argv) 17 { 18 struct pollfd fds[IN_FILES]; 19 char buf[MAX_BUFFER_SIZE]; 20 int i, res, real_read, maxfd; 21 fds[0].fd = 0; 22 if((fds[1].fd = open("data1", O_RDONLY|O_NONBLOCK)) < 0) { 23 fprintf(stderr, "open data1 error:%s", strerror(errno)); 24 return 1; 25 } 26 if((fds[2].fd = open("data2", O_RDONLY|O_NONBLOCK)) < 0) { 27 fprintf(stderr, "open data2 error:%s", strerror(errno)); 28 return 1; 29 } 30 31 for(i=0;i<IN_FILES;i++) 32 fds[i].events = POLLIN; 33 34 while(fds[0].events || fds[1].events || fds[2].events) { 35 if(poll(fds, IN_FILES, TIME_DELAY) <= 0) { 36 printf("Poll error\n"); 37 return 1; 38 } 39 for(i=0;i<IN_FILES;i++) { 40 if(fds[i].revents) { 41 memset(buf, 0, MAX_BUFFER_SIZE); 42 real_read = read(fds[i].fd, buf, MAX_BUFFER_SIZE); 43 if(real_read < 0) { 44 if(errno != EAGAIN) 45 return 1; 46 } else if(!real_read) { 47 close(fds[i].fd); 48 fds[i].events = 0; 49 } else { 50 if(i == 0) { 51 if((buf[0] == 'q') || (buf[0] == 'Q')) 52 return 1; 53 } else { 54 buf[real_read] = '\0'; 55 printf("%s", buf); 56 } 57 } 58 } 59 60 } 61 } 62 exit(0); 63 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include "unp.h" 2 #include <limits.h> 3 4 int 5 main(int argc, char **argv) 6 { 7 int i, maxi, listenfd, connfd, sockfd; 8 int nready; 9 ssize_t n; 10 char buf[MAXLINE]; 11 socklen_t clilen; 12 struct pollfd client[OPEN_MAX]; 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 client[0].fd = listenfd; 27 client[0].events = POLLRDNORM; 28 for(i=1;i<OPEN_MAX;i++) 29 client[i].fd = -1; 30 maxi = 0; 31 32 for( ; ; ) { 33 nready = Poll(client, maxi+1, INFTIM); 34 35 if(client[0].revents & POLLRDNORM) { 36 clilen = sizeof(cliaddr); 37 connfd = Accept(listenfd, (SA *)&cliaddr, &clilen); 38 39 for(i=1;i<OPEN_MAX;i++) 40 if(client[i].fd < 0) { 41 client[i].fd = connfd; 42 break; 43 } 44 if(i == OPEN_MAX) 45 err_quit("too many clients"); 46 47 client[i].events = POLLRDNORM; 48 if(i > maxi) 49 maxi = i; 50 51 if(--nready <= 0) 52 continue; 53 } 54 for(i = 1;i<=maxi;i++) { 55 if((sockfd = client[i].fd) < 0) 56 continue; 57 if(client[i].revents & (POLLRDNORM | POLLERR)) { 58 if((n = read(sockfd, buf, MAXLINE)) < 0) { 59 if(errno = ECONNRESET) { 60 Close(sockfd); 61 client[i].fd = -1; 62 } else 63 err_sys("read error"); 64 } else if(n == 0) { 65 Close(sockfd); 66 client[i].fd = -1; 67 } else 68 Writen(sockfd, buf, n); 69 70 if(--nready <= 0) 71 break; 72 } 73 } 74 } 75 }
无欲速,无见小利。欲速,则不达;见小利,则大事不成。