运行《深入理解计算机系统》的代码

以echo服务端与客户端为例

《深入理解计算机系统》(第三版)一书中提供了很多代码实例,但我一直没有运行过。现在就以第11章 P662 “echo客户端和服务端的示例”为例运行一下。

本次实验均在 WSL2 的 Ubuntu-22.04 系统上进行。

准备头文件

该书中的许多代码都包含了一个名为csapp.h的头文件。Linux系统本身并不包含它,需要自行准备。

下载源代码

点击此处 进入本书配套的网站,找到You can download a tarfile字段,点击链接下载压缩文件。

配套网站

配置环境

接下来需要将下载的压缩包中csapp.hcsapp.c文件解压出来,放到系统的/usr/include文件夹中。

先进入csapp.hcsapp.c所在的文件夹,然后执行:

1sudo mv csapp.h /usr/include
2sudo mv csapp.c /usr/include

此时,应该能在/usr/include看到这两个文件。

编译并运行

源代码

echoserveri.c文件:

 1/* 
 2 * echoserveri.c - An iterative echo server 
 3 */ 
 4/* $begin echoserverimain */
 5#include "csapp.h"
 6
 7void echo(int connfd) 
 8{
 9    size_t n; 
10    char buf[MAXLINE]; 
11    rio_t rio;
12
13    Rio_readinitb(&rio, connfd);
14    while((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) { //line:netp:echo:eof
15        printf("server received %d bytes\n", n);
16        Rio_writen(connfd, buf, n);
17    }
18}
19
20int main(int argc, char **argv) 
21{
22    int listenfd, connfd, port, clientlen;
23    struct sockaddr_in clientaddr;
24    struct hostent *hp;
25    char *haddrp;
26    if (argc != 2) {
27        fprintf(stderr, "usage: %s <port>\n", argv[0]);
28        exit(0);
29    }
30    port = atoi(argv[1]);
31
32    listenfd = Open_listenfd(port);
33    while (1) {
34        clientlen = sizeof(clientaddr);
35        connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);
36
37        /* determine the domain name and IP address of the client */
38        hp = Gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr, 
39                sizeof(clientaddr.sin_addr.s_addr), AF_INET);
40        haddrp = inet_ntoa(clientaddr.sin_addr);
41        printf("server connected to %s (%s)\n", hp->h_name, haddrp);
42
43        echo(connfd);
44        Close(connfd);
45    }
46    exit(0);
47}
48/* $end echoserverimain */

echoclient.c文件

 1/*
 2 * echoclient.c - An echo client
 3 */
 4/* $begin echoclientmain */
 5#include "csapp.h"
 6
 7int main(int argc, char **argv) 
 8{
 9    int clientfd, port;
10    char *host, buf[MAXLINE];
11    rio_t rio;
12
13    if (argc != 3) {
14        fprintf(stderr, "usage: %s <host> <port>\n", argv[0]);
15        exit(0);
16    }
17    host = argv[1];
18    port = atoi(argv[2]);
19
20    clientfd = Open_clientfd(host, port);
21    Rio_readinitb(&rio, clientfd);
22
23    while (Fgets(buf, MAXLINE, stdin) != NULL) {
24        Rio_writen(clientfd, buf, strlen(buf));
25        Rio_readlineb(&rio, buf, MAXLINE);
26        Fputs(buf, stdout);
27    }
28    Close(clientfd); //line:netp:echoclient:close
29    exit(0);
30}
31/* $end echoclientmain */

生成可执行文件

执行命令

1gcc echoserveri.c -o echoserveri
2gcc echoclient.c -o echoclient

得到可执行文件echoserveriechoclient

运行服务端和客户端

新建两个终端,分别运行echoserveriechoclient文件。

服务端终端:

1# 服务端启动时输入端口号
2./echoserveri <port>

客户端终端:

1# 客户端启动时输入主机名和端口号
2./echoclient <host> <port>
3
4# 之后可以输入内容
5# 观察服务端终端的内容

运行结果

服务端输出结果

客户端输出结果

Licensed under CC BY-NC-SA 4.0
网站总访客数:Loading

使用 Hugo 构建
主题 StackJimmy 设计