unix网络编程代码(3)

继续在博客上帖《unix网络编程》上的示例代码。和上一篇博文一样,本次实现的是一个反射程序。上一篇博文中的反射程序采用tcp、多进程实现,此次使用I/O复用技术(select)来实现。

头文件wrap.h同上一篇帖子。

服务端代码:

 1 #include "wrap.h"
 2 #define SER_PORT      9375
 3 
 4 int main ()
 5 {
 6     int i,maxi,maxfd,listenfd,connfd,sockfd;
 7     int nready,client[FD_SETSIZE];
 8     ssize_t n;
 9     fd_set rset,allset;
10     char buf[MAXLINE];
11     socklen_t clilen;
12     struct sockaddr_in cliaddr,seraddr;
13     
14     listenfd = Socket (AF_INET,SOCK_STREAM,0);
15     bzero (&cliaddr,sizeof (cliaddr));
16     bzero (&seraddr,sizeof (seraddr));
17 
18     seraddr.sin_family = AF_INET;
19     seraddr.sin_port = htons (SER_PORT);
20     seraddr.sin_addr.s_addr = htonl (INADDR_ANY);
21 
22     Bind (listenfd,&seraddr,sizeof (seraddr));
23     Listen (listenfd,1000);
24 
25     maxfd = listenfd;
26     maxi = -1;
27     for (i = 0;i < FD_SETSIZE;i ++) {
28         client[i] = -1;
29     }
30     FD_ZERO (&allset);
31     FD_SET (listenfd,&allset);
32 
33     while (1) {
34         rset = allset; /*structure assignment*/
35         nready = select (maxfd + 1,&rset,NULL,NULL,NULL);
36         //test 
37         printf ("select returned\n");
38         /*a new connection comes*/
39         if (FD_ISSET (listenfd,&rset)) {
40             clilen = sizeof (cliaddr);
41             connfd = Accept (listenfd,&cliaddr,&clilen);
42 
43             for (i = 0;i < FD_SETSIZE;i ++) {
44                 if (client[i] < 0) {
45                     client[i] = connfd;
46                     break;
47                 }
48             }
49 
50             if (i == FD_SETSIZE) {
51                 printf ("too many client\n");
52             }
53             /*add new descriptor in set*/
54             FD_SET (connfd,&allset);
55 
56             if (connfd > maxfd)
57                 maxfd = connfd;
58             if (i > maxi) 
59                 maxi = i;
60             /*no more readable descriptors*/
61             if (--nready <= 0)
62                 continue;
63         }
64         /*check all client for data*/
65         for (i = -1;i <= maxi;i ++) {
66             if (i == -1) 
67                 i ++;
68 
69             if ((sockfd = client[i]) < 0)
70                 continue;
71             if (FD_ISSET (sockfd,&rset)) {
72                 if ((n = read (sockfd,buf,MAXLINE)) == 0) {
73                     /*connection closed by client*/
74                     close (sockfd);
75                     FD_CLR (sockfd,&allset);
76                     client[i] = -1;
77                 } else {
78                     writen (sockfd,buf,n);
79                 }
80 
81                 if (--nready <= 0)
82                     break;
83             }
84         }
85     }
86 }

客户端代码:

 1 #include "wrap.h"
 2      
 3 #define SER_PORT      9375
 4 
 5 void str_cli (FILE *fp,int connfd);
 6 
 7 int main ()
 8 {
 9     int sockfd;
10     char *ip = "127.0.0.1";
11     struct sockaddr_in seraddr;
12 
13     sockfd = Socket (AF_INET,SOCK_STREAM,0);
14 
15     seraddr.sin_family = AF_INET;
16     seraddr.sin_port = htons (SER_PORT);
17     inet_pton (AF_INET,ip,&seraddr.sin_addr);
18 
19     Connect (sockfd,&seraddr,sizeof (seraddr));
20     str_cli (stdin,sockfd);
21 
22     return 0;
23 }
24 
25 void str_cli (FILE *fp,int connfd)
26 {
27     int maxfpd1,stdineof;
28     fd_set rset;
29     char buf[MAXLINE];
30     int n;
31 
32     stdineof = 0;
33     while (1) {
34         if (stdineof == 0) 
35             FD_SET (fileno (fp),&rset);
36         FD_SET (connfd,&rset);
37         maxfpd1 = Max (fileno (fp),connfd) + 1;
38         select (maxfpd1,&rset,NULL,NULL,NULL);
39 
40         if (FD_ISSET (connfd,&rset)) {
41             if ((n = read (connfd,buf,MAXLINE)) == 0) {
42                 if (stdineof == 1) 
43                     return;
44                 else {
45                     printf ("str_cli:server terminated too early");
46                     exit (1);
47                 }
48             }
49             write (fileno (stdout),buf,n);
50         } 
51 
52         if (FD_ISSET (fileno (fp),&rset)) {
53             if ((n = read (fileno (fp),buf,MAXLINE)) == 0) {
54                 stdineof = 1;
55                 shutdown (connfd,SHUT_WR);
56                 FD_CLR (fileno (fp),&rset);
57                 continue;
58             }
59 
60             writen (connfd,buf,n);
61         }
62     }
63 }

 

代码中有一些问题:

(1)在服务端代码中,如果read函数调用失败,select是无法报告给我们的,因为把select的相关参数设置为空了。

  (2)并没有使用select监视写操作(对于程序来说的写操作,就是程序向外界写如数据,比如文件、标准输出、标准错误流、套接字等),而仅仅是使用了write函数发送数据。

 

代码中有不完善的地方,请多指教。

posted @ 2016-02-13 12:53  纪老猴子  阅读(239)  评论(0编辑  收藏  举报