使用poll來實現回射程序,前幾篇的博文中的客戶端代碼均可以用,僅僅須要修改一下ip地址和端口號。編程
1 #include <poll.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include <netinet/in.h> 6 #include <arpa/inet.h> 7 #include <sys/socket.h> 8 #include <sys/types.h> 9 #include <errno.h> 10 #include <strings.h> 11 12 #define SER_PORT 9374 13 #define OPEN_MAX 4096 14 #define MAXLINE 200 15 16 ssize_t writen (int fd,void *vptr,size_t n); 17 18 int main () 19 { 20 int i,maxi,listenfd,sockfd,connfd; 21 int nready; 22 ssize_t n; 23 char buf[MAXLINE]; 24 socklen_t clilen; 25 struct pollfd client[OPEN_MAX]; 26 struct sockaddr_in seraddr,cliaddr; 27 const int on = 1; 28 29 bzero (&seraddr,sizeof (seraddr)); 30 bzero (&cliaddr,sizeof (cliaddr)); 31 32 seraddr.sin_family = AF_INET; 33 seraddr.sin_addr.s_addr = htonl (INADDR_ANY); 34 seraddr.sin_port = htons (SER_PORT); 35 36 if ((listenfd = socket (AF_INET,SOCK_STREAM,0)) < 0) { 37 perror ("socket"); 38 exit (1); 39 } 40 41 if ((setsockopt (listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof (on))) < 0) { 42 perror ("setsockopt"); 43 exit (1); 44 } 45 46 if ((bind (listenfd,(struct sockaddr*) &seraddr,sizeof (seraddr))) < 0) { 47 perror ("bind"); 48 exit (1); 49 } 50 51 if ((listen (listenfd,200)) < 0) { 52 perror ("listen"); 53 exit (1); 54 } 55 56 client[0].fd = listenfd; 57 client[0].events = POLLRDNORM; 58 for (int i = 1;i < OPEN_MAX;i ++) { 59 client[i].fd = -1; 60 } 61 maxi = 0; 62 63 while (1) { 64 if ((nready = poll (client,maxi + 1,-1)) < 0) { 65 perror ("poll"); 66 exit (1); 67 } 68 69 if (client[0].revents & POLLRDNORM) { 70 int j; 71 clilen = sizeof (cliaddr); 72 connfd = accept (listenfd,(struct sockaddr*)&cliaddr,&clilen); 73 74 for (int i = 1;i < OPEN_MAX;i++) { 75 if (client[i].fd < 0) { 76 client[i].fd = connfd; 77 j = i; 78 break; 79 } 80 } 81 82 if (j == OPEN_MAX) 83 exit (0); 84 85 client[j].events = POLLRDNORM; 86 if (maxi < j) 87 maxi = j; 88 if (--nready <= 0) 89 continue; 90 } 91 92 for (int i = 1;i <= maxi;i ++) { 93 if ((sockfd = client[i].fd) < 0) 94 continue; 95 if (client[i].revents & (POLLRDNORM | POLLERR)) { 96 if ((n = read (sockfd,buf,MAXLINE)) < 0) { 97 if (errno = ECONNRESET) { 98 /*connection reset by client*/ 99 close (sockfd); 100 client[i].fd = -1; 101 printf ("a connection reseted\n"); 102 } else { 103 exit (1); 104 } 105 } else if (n == 0) { 106 /*connection closed by client*/ 107 close (sockfd); 108 client[i].fd = -1; 109 printf ("a connection closed\n"); 110 } else { 111 printf ("%s\n",buf); 112 writen (sockfd,buf,n); 113 } 114 115 if (--nready <= 0) 116 break; 117 } 118 } 119 } 120 } 121 122 ssize_t writen (int fd,void *vptr,size_t n) 123 { 124 size_t nleft; 125 ssize_t nwritten; 126 const char *ptr; 127 128 ptr = vptr; 129 nleft = n; 130 while (nleft > 0) { 131 if ((nwritten = write (fd,ptr,nleft)) <= 0) { 132 /*nothing written or an error occured*/ 133 if (nwritten < 0 && errno == EINTR) { 134 /* 135 *The call was interrupted by a signal before any data was read 136 *and call it again. 137 */ 138 nwritten = 0; 139 } else { 140 /*the call was interrupted by other signal,return -1*/ 141 return (-1); 142 } 143 } 144 145 nleft -= nwritten; 146 ptr += nwritten; 147 } 148 149 return (n); 150 }
poll監聽的是結構struct pollfd數組中設置的文件描述符。在《unix網絡編程》,W. Richard Stevens博士添加了limits.h,該頭文件中有一個宏定義OPEN_MAX,該宏的意思是:任何一個運行中的程序可以同時打開的文件數是有限制的,這個限制一般是由limits.h頭文件中的常量OPEN_MAX定義的,它的值隨系統的不一樣而不一樣,但POSIX要求它至少爲16。在個人debian的limits.h頭文件沒有找到這個宏,後來谷歌了一下,在OPEN_MAX已經取消,已經變成了資源限制RLIMIT_NOFILE的一部分。