繼續在博客上帖《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