基于TCP的一对回射客户/服务器程序及其运行过程分析( 上 )

时间:2022-12-15 10:09:20

前言

  本文将讲解一对经典的客户/服务器回射程序,感受网络编程的大致框架( 该程序稍作改装即可演变成各种提供其他服务的程序 );同时,还将对其运行过程加以分析,观察程序背后协议的执行细节,学习调试网络程序的技巧。

客户端

 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 }