第十篇:基於TCP的一對回射客戶/伺服器程式及其執行過程分析( 上 )

穆晨發表於2017-01-29

前言

       本文將講解一對經典的客戶/伺服器回射程式,感受網路程式設計的大致框架( 該程式稍作改裝即可演變成各種提供其他服務的程式 );同時,還將對其執行過程加以分析,觀察程式背後協議的執行細節,學習除錯網路程式的技巧。

客戶端

 1 #include    "unp.h"
 2 
 3 void str_cli(FILE *fp, int sockfd);
 4 
 5 int
 6 main(int argc, char **argv)
 7 {
 8     int                    sockfd;
 9     struct sockaddr_in    servaddr;
10 
11     if (argc != 2)
12         err_quit("usage: tcpcli <IPaddress>");
13 
14     sockfd = Socket(AF_INET, SOCK_STREAM, 0);
15 
16     bzero(&servaddr, sizeof(servaddr));
17     servaddr.sin_family = AF_INET;
18     servaddr.sin_port = htons(SERV_PORT);
19     Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
20 
21     Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));
22 
23     str_cli(stdin, sockfd);    
24 
25     exit(0);
26 }
27 
28 /*
29  * 事務函式
30 */
31 void
32 str_cli(FILE *fp, int sockfd)
33 {
34     char    sendline[MAXLINE], recvline[MAXLINE];
35 
36     // 從標準輸入讀取字串( 阻塞於使用者 )    
37     while (Fgets(sendline, MAXLINE, fp) != NULL) {
38 
39         // 往緩衝區寫入字串
40         Writen(sockfd, sendline, strlen(sendline));
41 
42         // 從緩衝區讀取字串( 阻塞於伺服器傳回的資料 )
43         if (Readline(sockfd, recvline, MAXLINE) == 0)
44             err_quit("str_cli: server terminated prematurely");
45 
46         // 讀取從伺服器回射的訊息並在終端列印
47         Fputs(recvline, stdout);
48     }
49 }

伺服器端

 1 #include    "unp.h"
 2 
 3 void str_echo(int sockfd);
 4 
 5 int
 6 main(int argc, char **argv)
 7 {
 8     int                    listenfd, connfd;
 9     pid_t                childpid;
10     socklen_t            clilen;
11     struct sockaddr_in    cliaddr, servaddr;
12 
13     listenfd = Socket(AF_INET, SOCK_STREAM, 0);
14 
15     bzero(&servaddr, sizeof(servaddr));
16     servaddr.sin_family      = AF_INET;
17     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
18     servaddr.sin_port        = htons(SERV_PORT);
19 
20     Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
21 
22     Listen(listenfd, LISTENQ);
23 
24     for ( ; ; ) {
25         clilen = sizeof(cliaddr);
26         connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
27 
28         if ( (childpid = Fork()) == 0) {    /* 子程式處理段 */
29             Close(listenfd);    /* 關閉監聽套接字 */
30             str_echo(connfd);    /* 事務處理 */
31             exit(0);
32         }
33         Close(connfd);            /* 父程式關閉連線套接字 */
34     }
35 }
36 
37 /*
38  * 事務處理函式
39 */
40 void
41 str_echo(int sockfd)
42 {
43     ssize_t        n;
44     char        buf[MAXLINE];
45 
46 again:
47     while ( (n = read(sockfd, buf, MAXLINE)) > 0)
48         Writen(sockfd, buf, n);
49 
50     if (n < 0 && errno == EINTR)
51         goto again;
52     else if (n < 0)
53         err_sys("str_echo: read error");
54 }

相關文章