国庆假期里没什么事情, 花了点时间完成了 csapp 的 proxy lab, 实现了一个 http 代理服务器. 原理非常简单, 就是把客户端发来的请求转发给目标主机, 然后把目标主机发来的响应再转发给客户端.

转发请求

以前一直不太理解代理服务器是怎么获得客户端的请求. 现在才知道一次 http 请求其实是分成两步. 第一步是和目标主机建立联系, 第二步才是请求目标主机 上的资源. 所谓代理, 就是客户端先和代理服务器建立联系, 然后请求目标主机 资源, 再由代理服务器代为转发.

img

这里也解释了 URL 和 URI 的区别. URL 分成两部分, 一部分是 hostname 和 port, 用于说明目标主机; 另一部分就是 URI, 指明所要请求的目标主机上的资 源. 比如 URL “https://www.archwiki.org/index.php”, 其中 “https://www.archwiki.org” 就是目标主机, 而 “/index.php” 就是 URI.

转发 http 请求的时候, 发送的数据需要符合 http 协议的要求. 详细的格式可 以参见 http 的 RFC, 这个作业里只要求转发 GET 方法就行了.

并发

这里采用了子进程方式实现多客户端并发访问. 多线程和I/O多路复用都可以实 现并发, 子进程是最简单的方式.

信号处理

由于采用了子进程来实现并发, 所以父进程必须要回收已结束的子进程. 捕获并 处理 SIGCHLD 信号就可以了.

此外, 如果服务器向一个已被客户端关闭了的连接写入, 第一次写入会正常返回, 而第二次写会引发 SIGPIPE 信号, 而这个信号默认会终止这个进程. 捕获或忽 略 SIGPIPE 后 errno 会被设置为 EPIPE. csapp 提供的 Rio 包已处理了由信 号引起的读写中断, 所以把 SIGPIPE 信号的默认行为改为忽略即可.