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

以echo服务端与客户端为例

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

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

准备头文件

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

下载源代码

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

配套网站

配置环境

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

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

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

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

编译并运行

源代码

echoserveri.c文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/* 
 * echoserveri.c - An iterative echo server 
 */ 
/* $begin echoserverimain */
#include "csapp.h"

void echo(int connfd) 
{
    size_t n; 
    char buf[MAXLINE]; 
    rio_t rio;

    Rio_readinitb(&rio, connfd);
    while((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) { //line:netp:echo:eof
        printf("server received %d bytes\n", n);
        Rio_writen(connfd, buf, n);
    }
}

int main(int argc, char **argv) 
{
    int listenfd, connfd, port, clientlen;
    struct sockaddr_in clientaddr;
    struct hostent *hp;
    char *haddrp;
    if (argc != 2) {
        fprintf(stderr, "usage: %s <port>\n", argv[0]);
        exit(0);
    }
    port = atoi(argv[1]);

    listenfd = Open_listenfd(port);
    while (1) {
        clientlen = sizeof(clientaddr);
        connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);

        /* determine the domain name and IP address of the client */
        hp = Gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr, 
                sizeof(clientaddr.sin_addr.s_addr), AF_INET);
        haddrp = inet_ntoa(clientaddr.sin_addr);
        printf("server connected to %s (%s)\n", hp->h_name, haddrp);

        echo(connfd);
        Close(connfd);
    }
    exit(0);
}
/* $end echoserverimain */

echoclient.c文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*
 * echoclient.c - An echo client
 */
/* $begin echoclientmain */
#include "csapp.h"

int main(int argc, char **argv) 
{
    int clientfd, port;
    char *host, buf[MAXLINE];
    rio_t rio;

    if (argc != 3) {
        fprintf(stderr, "usage: %s <host> <port>\n", argv[0]);
        exit(0);
    }
    host = argv[1];
    port = atoi(argv[2]);

    clientfd = Open_clientfd(host, port);
    Rio_readinitb(&rio, clientfd);

    while (Fgets(buf, MAXLINE, stdin) != NULL) {
        Rio_writen(clientfd, buf, strlen(buf));
        Rio_readlineb(&rio, buf, MAXLINE);
        Fputs(buf, stdout);
    }
    Close(clientfd); //line:netp:echoclient:close
    exit(0);
}
/* $end echoclientmain */

生成可执行文件

执行命令

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

得到可执行文件echoserveriechoclient

运行服务端和客户端

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

服务端终端:

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

客户端终端:

1
2
3
4
5
# 客户端启动时输入主机名和端口号
./echoclient <host> <port>

# 之后可以输入内容
# 观察服务端终端的内容

运行结果

服务端输出结果

客户端输出结果

网站总访客数:Loading

使用 Hugo 构建
主题 StackJimmy 设计