docs: 全面审查并修正所有章节文档内容

- 修正各章节中的错别字和术语错误(如 IPv4 大写规范、接收/接受区分等)
- 补充和完善部分习题答案
- 优化技术描述的准确性和专业性
- 合并所有章节内容到根 README.md

新增文件:
- CLAUDE.md: 项目开发指南
- .claude/agents/content-reviewer.md: 内容审查 subagent
- .claude/agents/merger.md: 文档合并 subagent

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
riba2534
2026-01-05 15:28:29 +08:00
parent f163bca3a9
commit d44ecdf807
23 changed files with 1933 additions and 825 deletions

View File

@@ -10,7 +10,7 @@ TCP 的断开连接过程比建立连接更重要,因为连接过程中一般
#### 7.1.1 单方面断开连接带来的问题
Linux 和 Windows 的 closesocket 函数意味着完全断开连接。完全断开不仅指无法传输数据,而且也不能接收数据。因此在某些情况下,通信一方单方面的断开套接字连接,显得不太优雅。如图所示:
Linux 的 close 函数和 Windows 的 closesocket 函数意味着完全断开连接。完全断开不仅指无法传输数据,而且也不能接收数据。因此在某些情况下,通信一方单方面的断开套接字连接,显得不太优雅。如图所示:
![](https://i.loli.net/2019/01/18/5c412a8baa2d8.png)
@@ -22,11 +22,11 @@ Linux 和 Windows 的 closesocket 函数意味着完全断开连接。完全断
两台主机通过套接字建立连接后进入可交换数据的状态,又称「流形成的状态」。也就是把建立套接字后可交换数据的状态看作一种流。
此处的流可以比作水流。水朝着一个方向流动,同样,在套接字的流中,数据也止呕能向一个方向流动。因此,为了进行双向通信,需要如图所示的两个流:
此处的流可以比作水流。水朝着一个方向流动,同样,在套接字的流中,数据也能向一个方向流动。因此,为了进行双向通信,需要如图所示的两个流:
![](https://i.loli.net/2019/01/18/5c412c3ba25dd.png)
一旦两台主机之间建立了套接字连接,每个主机就会拥有单独的输入流和输出流。当然,其中一个主机的输入流与另一个主机的输出流相连,而输出流则与另一个主机的输入流相连。另外,本章讨论的「优雅的断开连接方式」只断开其中 1 个流而非同时断开两个流。Linux 和 Windows 的 closesocket 函数将同时断开这两个流,因此与「优雅」二字还有一段距离。
一旦两台主机之间建立了套接字连接,每个主机就会拥有单独的输入流和输出流。当然,其中一个主机的输入流与另一个主机的输出流相连,而输出流则与另一个主机的输入流相连。另外,本章讨论的「优雅的断开连接方式」只断开其中 1 个流而非同时断开两个流。Linux 的 close 函数和 Windows 的 closesocket 函数将同时断开这两个流,因此与「优雅」二字还有一段距离。
#### 7.1.3 针对优雅断开的 shutdown 函数
@@ -56,7 +56,7 @@ howto: 传递断开方式信息
> 一旦客户端连接到服务器服务器将约定的文件传输给客户端客户端收到后发送字符串「Thank you」给服务器端。
此处「Thank you」的传递是多余的这只是用来模拟客户端断开连接前还有数据要传输的情况。此时程序的还嫌难度并不小,因为传输文件的服务器端只需连续传输文件数据即可,而客户端无法知道需要接收数据到何时。客户端也没办法无休止的调用输入函数,因为这有可能导致程序**阻塞**。
此处「Thank you」的传递是多余的这只是用来模拟客户端断开连接前还有数据要传输的情况。此时程序的编写难度并不小,因为传输文件的服务器端只需连续传输文件数据即可,而客户端无法知道需要接收数据到何时。客户端也没办法无休止的调用输入函数,因为这有可能导致程序**阻塞**。
> 是否可以让服务器和客户端约定一个代表文件尾的字符?
@@ -94,7 +94,25 @@ gcc file_server.c -o fserver
### 7.2 基于 Windows 的实现
暂略
Windows 平台下的半关闭实现与 Linux 类似,同样使用 shutdown 函数。函数原型如下:
```c
#include <winsock2.h>
int shutdown(SOCKET s, int how);
/*
成功时返回 0失败时返回 SOCKET_ERROR
s: 需要断开的套接字句柄
how: 传递断开方式信息
*/
```
Windows 下的 how 参数取值与 Linux 略有不同:
- `SD_RECEIVE` : 断开输入流(相当于 Linux 的 SHUT_RD
- `SD_SEND` : 断开输出流(相当于 Linux 的 SHUT_WR
- `SD_BOTH` : 同时断开 I/O 流(相当于 Linux 的 SHUT_RDWR
使用方法与 Linux 版本基本一致,只需注意参数名称的差异即可。
### 7.3 习题
@@ -106,8 +124,14 @@ gcc file_server.c -o fserver
2. **Linux 中的 close 函数或 Windows 中的 closesocket 函数属于单方面断开连接的方法,有可能带来一些问题。什么是单方面断开连接?什么情形下会出现问题?**
答:单方面断开连接就是两台主机正在通信,其中一台主机关闭了所有连接,那么一台主机向另一台主机传输的数据可能会没有接收到而损毁。传输文件的服务器只需连续传输文件数据即可,而客户端不知道需要接收数据到何时。客户端也没有办法无休止的调用输入函数。现在需要一个 EOF 代表数据已经传输完毕,那么这时就需要半关闭,服务端把自己的输出流关了,这时客户端就知数据已经传输完毕,因为服务端的输入流还没关,客户端可以给服务器汇报,接收完毕
答:单方面断开连接是指通信的一方调用 closeLinux或 closesocketWindows函数同时关闭输入流和输出流。这会导致该主机既不能发送数据也不能接收数据
问题出现的典型情形是服务器向客户端传输文件传输完成后需要接收客户端的确认信息如「Thank you」。如果服务器调用 close 函数发送 EOF虽然客户端能知道文件传输完毕但服务器也无法再接收客户端发送的确认信息了。解决方法是使用 shutdown 函数进行半关闭,只关闭输出流,保留输入流。
3. **什么是半关闭?针对输出流执行半关闭的主机处于何种状态?半关闭会导致对方主机接收什么消息?**
答:半关闭就是把输入流或输出流关了。针对输出流执行半关闭的主机处于可以接收数据而不能发送数据。半关闭会导致对方主机接收一个 EOF 文件结束符。对方就知道你的数据已经传输完毕。
答:半关闭是指只关闭套接字的输入流或输出流中的一种,而不是同时关闭两者。
针对输出流执行半关闭(即调用 `shutdown(sock, SHUT_WR)`)的主机处于:可以接收数据,但无法发送数据的状态。
半关闭会导致对方主机的接收函数返回 EOF文件结束符对方主机由此得知数据已传输完毕。