服務器端select I/O多路複用模型

服務器Select模型的實現
標籤: 服務器socketmakefilestreamnullnetwork
服務器Select模型的實現
討論新聞組及文件

select模型屬於網絡的I/O複用模型,比純粹的阻塞I/O模型更具有實用性,<span style="color:#ff0000;">因爲可以同時等待多個描述字的就緒</span>。

當年學習C/C++的時候,很少碰到底層以數字標示的描述字,只在寫文件系統的去嘗試各種情況,以獲得最佳效率的時候實際嘗試使用過一次,一直覺得那種open,write,read的文件操作方式,實在是比fopen一族函數還要低級的方式-_-!平時沒有必要使用。但是等到網絡編程的時候,才發現。。。。原來這麼底層的東西,竟然也有一定的通用性,文件的描述字和網絡的描述字竟然是一致的-_-!不管是誰設計的,還是挺佩服的。。。。。。

       這裏僅僅是爲了學習Select模型而寫的學習例子,作用是在服務器端輸出連接上的客戶端的IP(僅以數字形式),然後將客戶端的IP以字符串的形式返回,客戶端連接服務器,並接受由服務器端返回的IP地址,然後輸出轉換爲字符串形式的IP地址和數字形式的IP地址,爲了區別select到正確的不同listen套接字,這裏用了不同的端口,並且不同的兩個套接字響應時以echo 1,echo 2區別。功能是很簡單的,僅僅用於學習,所以其中很多地方本來可以抽出來稱爲函數的,都貪簡單,直接複製了(-_-!這裏本來習慣想說Ctrl-C Ctrl-V的。。。但是發現自己實在Ubuntu下用vim複製的,好像和實際情況不符。。。。)

       另外。。。。由於用的是《Unix Network Programming》一書,所以編程風格都變得有點像書中了。。。。服務器端全是自己寫的,客戶端代碼由書中的daytime客戶端改過來的,並且發現書中客戶端代碼都不關閉套接字,都交由退出進程的時候由系統關閉,不知道這種風格好不好。由於學習。。。寫的是ANSI C程序,用gcc編譯-_-!

unp.h是《Unix Network Programming》源代碼中的公用頭文件,makefile可能也得注意一下,爲了圖省事,我用了其源代碼中的Make.defines,因爲這樣比自己寫簡單多了:),makefile就不貼了,沒有什麼學習意義。

 

運行效果如下:

客戶端運行:

./TestSelectCli 127.0.0.1 1000

Conncet OK

127.0.0.1:16777343 Echo 1.

laptop:~/unpv1/unpv13e/MyTest$ ./TestSelectCli 127.0.0.1 1001

Conncet OK

127.0.0.1:16777343 Echo 2.

laptop:~/unpv1/unpv13e/MyTest$ ./TestSelectCli 192.168.0.138 1000

Conncet OK

192.168.0.138:2315299008 Echo 1.

laptop:~/unpv1/unpv13e/MyTest$ ./TestSelectCli 192.168.0.138 1001

Conncet OK

192.168.0.138:2315299008 Echo 2.

 

服務器端輸出:

2315299008 Echo 1.

16777343 Echo 1.

16777343 Echo 2.

2315299008 Echo 1.

2315299008 Echo 2.

 

 

服務器端源代碼:

 

  1 #include    "unp.h"
  2 
  3 
  4 void str_echo1(int connfd);
  5 void str_echo2(int connfd);
  6 
  7 int main(int argc, char **argv)
  8 {
  9     struct sockaddr_in cliaddr;
 10     pid_t childpid;
 11 
 12     /*  Bind 1000 port to listen socket 1 */
 13     int listenfd1 = Socket(AF_INET, SOCK_STREAM, 0);
 14 
 15     struct sockaddr_in servaddr;
 16     bzero(&servaddr, sizeof(servaddr));
 17     servaddr.sin_family = AF_INET;
 18     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
 19     servaddr.sin_port = htons(1000);
 20 
 21     Bind(listenfd1, (SA *)&servaddr, sizeof(servaddr));
 22 
 23     Listen(listenfd1, LISTENQ);
 24 
 25     /*  Bind 1001 port to listen socket 2*/
 26     int listenfd2 = Socket(AF_INET, SOCK_STREAM, 0);
 27 
 28     struct sockaddr_in servaddr2;
 29     bzero(&servaddr2, sizeof(servaddr2));
 30     servaddr2.sin_family = AF_INET;
 31     servaddr2.sin_addr.s_addr = htonl(INADDR_ANY);
 32     servaddr2.sin_port = htons(1001);
 33 
 34     Bind(listenfd2, (SA *)&servaddr2, sizeof(servaddr2));
 35 
 36     Listen(listenfd2, LISTENQ);
 37 
 38     /* Initialize fd_set struct */
 39     int maxfdp1 = max(listenfd1, listenfd2) + 1;
 40     fd_set rset;
 41     FD_ZERO(&rset);
 42 
 43     /*  Select from this two listen socket */
 44     for( ; ; )
 45     {
 46         FD_SET(listenfd1, &rset);
 47         FD_SET(listenfd2, &rset);
 48 
 49         int nready = -1;
 50         if( (nready = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0)
 51         {
 52             if(EINTR == errno)
 53             {
 54                 continue;
 55             }
 56             else
 57             {
 58                 err_sys("Select error.");
 59             }
 60         }
 61 
 62         /*  some one listening socket is readable.*/
 63         if(FD_ISSET(listenfd1, &rset))
 64         {
 65             socklen_t len = sizeof(cliaddr);
 66             int connfd = Accept(listenfd1, (SA *)&cliaddr, &len);
 67 
 68             if( 0 == (childpid = Fork()) )
 69             {
 70                 /* child process */
 71                 Close(listenfd1);
 72 
 73                 str_echo1(connfd);
 74                 exit(0);
 75             }
 76 
 77             /* parent process  */
 78             Close(connfd);
 79 
 80         }
 81 
 82 
 83         if(FD_ISSET(listenfd2, &rset))
 84         {
 85             socklen_t len = sizeof(cliaddr);
 86             int connfd = Accept(listenfd2, (SA *)&cliaddr, &len);
 87 
 88             if( 0 == (childpid = Fork()) )
 89             {
 90                 /* child process */
 91                 Close(listenfd2);
 92 
 93                 str_echo2(connfd);
 94                 exit(0);
 95             }
 96 
 97             /* parent process  */
 98             Close(connfd);
 99 
100         }
101 
102     }
103 
104     exit(0);
105 }
106 
107 void str_echo1(int connfd)
108 {
109     struct sockaddr_in clientAddr;
110     socklen_t len = sizeof(clientAddr);
111 
112     if(getpeername(connfd, (SA*) &clientAddr, &len) < 0)
113     {
114         return;
115     }
116 
117     char lcBuffer[MAXLINE] = {0};
118     sprintf(lcBuffer, "%u Echo 1.", clientAddr.sin_addr.s_addr);
119 
120     printf("%s/n", lcBuffer);
121 
122     Write(connfd, lcBuffer, MAXLINE);
123 }
124 
125 
126 void str_echo2(int connfd)
127 {
128     struct sockaddr_in clientAddr;
129     socklen_t len = sizeof(clientAddr);
130 
131     if(getpeername(connfd, (SA*) &clientAddr, &len) < 0)
132     {
133         return;
134     }
135 
136 
137     char lcBuffer[MAXLINE] = {0};
138     sprintf(lcBuffer, "%u Echo 2.", clientAddr.sin_addr.s_addr);
139 
140     printf("%s/n", lcBuffer);
141 
142     Write(connfd, lcBuffer, MAXLINE);
143 }
144 
145

 

客戶端源代碼:

 1 #include    "unp.h"
 2 
 3 int main(int argc, char **argv)
 4 {
 5     int                    sockfd, n;
 6     char               recvline[MAXLINE + 1];
 7     struct sockaddr_in servaddr;
 8 
 9     if (argc != 3)
10         err_quit("usage: a.out <IPaddress> <IPPort>");
11 
12     int port = atoi(argv[2]);
13 
14     if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
15         err_sys("socket error");
16 
17     bzero(&servaddr, sizeof(servaddr));
18     servaddr.sin_family = AF_INET;
19     servaddr.sin_port   = htons(port);
20     if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
21         err_quit("inet_pton error for %s", argv[1]);
22 
23     if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)
24         err_sys("connect error");
25 
26     printf("Conncet OK/n");
27 
28     while ( (n = read(sockfd, recvline, MAXLINE)) > 0) {
29         recvline[n] = 0;  /* null terminate */
30 
31         /*  change number string to number and to ip string */
32         struct in_addr svraddr;
33         svraddr.s_addr = strtoul(recvline, NULL, 10);
34         char *pszsvraddr = inet_ntoa(svraddr);
35 
36         printf("%s:%s/n", pszsvraddr, recvline);
37     }
38     if (n < 0)
39         err_sys("read error");
40 
41     exit(0);
42 }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章