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