unix網絡編程代碼(3)

繼續在博客上帖《unix網絡編程》上的示例代碼。和上一篇博文同樣,本次實現的是一個反射程序。上一篇博文中的反射程序採用tcp、多進程實現,這次使用I/O複用技術(select)來實現。編程

頭文件wrap.h同上一篇帖子。網絡

服務端代碼:tcp

 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 }

 

代碼中有一些問題:spa

(1)在服務端代碼中,若是read函數調用失敗,select是沒法報告給咱們的,由於把select的相關參數設置爲空了。unix

  (2)並無使用select監視寫操做(對於程序來講的寫操做,就是程序向外界寫如數據,好比文件、標準輸出、標準錯誤流、套接字等),而僅僅是使用了write函數發送數據。code

 

代碼中有不完善的地方,請多指教。server

相關文章
相關標籤/搜索