资讯动态

CS-144 checkpoint 0: networking warmup

发布时间:2026/10/8 18:55:16 来源:尧图企业网站定制
Writing a network program using an OS stream socket2026-10-07 · 完成 checkpoint 0 的第一部分用 OS 提供的 stream socket 写一个最小化的 HTTP 客户端webget。实验目标Checkpoint 0 是整个 CS144 的热身关目标有两个层次表层写一个叫webget的程序用操作系统内核现成的 TCP 支持连上 Web 服务器、抓取一个页面——和之前在 telnet 里手工敲 HTTP 请求做的事一模一样只是这次用 C 代码完成。深层让学习者亲眼看清楚可靠字节流这个抽象。Internet 本身只提供 best-effort 的数据报投递——数据报可能丢失、乱序、内容被篡改、甚至被重复投递把它变成可靠、有序的字节流的是两端操作系统上运行的 TCP。这个热身关用的是现成的 TCP而从后面的 checkpoint 开始我们要亲手把这个抽象造出来ByteStream → Reassembler → TCP Receiver/Sender。前置知识1. stream socket 是什么长得像文件描述符的字节流对程序来说socket 就是一个普通的文件描述符。两个 socket 建立连接后一方write进去的字节最终会按同样的顺序从另一方的 socket 里被read出来。传输过程中 TCP 替我们处理了分段、重传、排序、流量控制等一切脏活。2. HTTP 请求就是一段文本先用 telnet 手工体验过一遍telnet cs144.keithw.org http后逐行敲GET /hello HTTP/1.1 Host: cs144.keithw.org Connection: close 空行要点请求行 头字段 空行每一行都以\r\n结尾不是\n空行标志请求头结束服务器据此判断请求发完了Connection: close告诉服务器回完这个响应就关闭连接——这正是后面客户端能知道读完了的关键。3. 一个贯穿全程的对照connect()就是三次握手connect()返回时TCP 的 SYN / SYN-ACK / ACK 三次握手已经完成。数据可靠性不是免费的连接建立这一步本身就是协议在谈条件同步序列号、确认双方可达。实现思路get_URL(host, path)分四步走预约一个 endpointTCPSocket tcpSocket;—— 构造时调用socket(2)拿到一个未连接的 TCP socketfile descriptor。把名字翻译成地址Address address(host, http);—— 一次搞定两层解析主机名 → IP 地址服务名http→ 端口号 80。发起连接tcpSocket.connect(address);—— 触发三次握手。收发文本按 HTTP 规定的文本格式拼好请求GET path HTTP/1.1Host:Connection: close 空行全部\r\nwrite()出去——注意write只是把字节交给内核的发送缓冲区之后的可靠交付由 TCP 负责循环read()并立刻打印直到eof()。EOF 的语义对端服务器关闭连接后本端read返回 0 字节 →eof()为真 → 循环结束。所以Connection: close不仅是对服务器说回完就关也是在为客户端自己的读循环安排一个确定的终点。代码实现/* * apps/webget.cc */voidget_URL(conststringhost,conststringpath){// 预约一个 end-point (file-descriptor)TCPSocket tcpSocket;// 将域名解析为 IP 地址将服务名解析为端口号Addressaddress(host,http);// tcp 触发三次握手tcpSocket.connect(address);// 请求文本std::string require_strGET path HTTP/1.1\r\nHost: host\r\nConnection: close\r\n\r\n;// write 把请求文本写入内核的发送缓存区交给 tcp 处理后续工作tcpSocket.write(require_str);// read 读取后立刻打印std::string buffer;while(!tcpSocket.eof()){tcpSocket.read(buffer);coutbuffer;}}值得注意的两个点RAII全程没有close()调用——TCPSocket析构时自动关闭文件描述符这也是本课程反复强调的现代 C 风格构造获取资源、析构释放资源。请求串用\r\n拼接、以\r\n\r\n收尾这里错一个字符服务器就不知道该在哪儿停下来。验证构建cmake --build build或cmake --build build --target webget。自动测试cmake --build build --target check_webget等价于ctest -R webget。测试脚本tests/webget_t.sh会让webget去抓cs144.keithw.org/nph-hasher/xyzzy取输出的最后一行与一个已知哈希比对——所以输出必须和服务器返回的字节流一字不差。手动验证./apps/webget cs144.keithw.org /hello应看到和浏览器、telnet 完全一样的响应HTTP 头 正文。复盘HTTP 没有魔法。浏览器做的事、telnet 做的事、webget 做的事本质完全相同在一条字节流上按约定格式写一段文本再读回一段文本。理解了这一点后面的 lab 就都建立在这条字节流之上。EOF 是对端关闭连接的协议信号不是数据的自然属性。read返回 0 依赖服务器真的把连接关了而服务器肯关是因为我们发了Connection: close——客户端和服务器在字节流之上又叠了一层文本协议来协调行为。connect()返回 ≠ 数据到了。它只是完成了三次握手之后每次write的可靠交付都是内核里 TCP 状态机在背后工作。从 checkpoint 1 起这台状态机将由我们自己在用户态实现。小步提交。handout 强调频繁、语义化的小 commit——今天这个 commit 只做了一件事get_URL从未实现变成能抓页面每个 commit 都可编译、都朝测试通过的方向前进。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑