unix网络编程代码(6)

使用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的一部分。
posted @ 2016-02-29 17:08  纪老猴子  阅读(115)  评论(0编辑  收藏  举报