From abe41d5c583f69800f586ebb874b5e33d9915abb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8A=E5=AE=98=E6=B0=B8=E7=9F=B3?= <841842619@qq.com> Date: Mon, 4 Jul 2022 20:18:30 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20ch02=20=E9=94=99?= =?UTF-8?q?=E5=88=AB=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch02/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ch02/README.md b/ch02/README.md index 85fc752..cbae132 100644 --- a/ch02/README.md +++ b/ch02/README.md @@ -83,13 +83,13 @@ socket 函数的第三个参数决定最终采用的协议。前面已经通过 > 可以应对同一协议族中存在的多个数据传输方式相同的协议,所以数据传输方式相同,但是协议不同,需要用第三个参数指定具体的协议信息。 -本书用的是 Ipv4 的协议族,和面向连接的数据传输,满足这两个条件的协议只有 TPPROTO_TCP ,因此可以如下调用 socket 函数创建套接字,这种套接字称为 TCP 套接字。 +本书用的是 Ipv4 的协议族,和面向连接的数据传输,满足这两个条件的协议只有 IPPROTO_TCP ,因此可以如下调用 socket 函数创建套接字,这种套接字称为 TCP 套接字。 ```c int tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); ``` -SOCK_DGRAM 指的是面向消息的数据传输方式,满足上述条件的协议只有 TPPROTO_UDP 。这种套接字称为 UDP 套接字: +SOCK_DGRAM 指的是面向消息的数据传输方式,满足上述条件的协议只有 IPPROTO_UDP 。这种套接字称为 UDP 套接字: ```c int udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); From ceae1e9a24ca609e2c4f463ae212149ab295b16f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8A=E5=AE=98=E6=B0=B8=E7=9F=B3?= <841842619@qq.com> Date: Mon, 4 Jul 2022 20:19:19 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20ch03=20=E9=83=A8?= =?UTF-8?q?=E5=88=86=E8=A1=A8=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch03/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ch03/README.md b/ch03/README.md index 05b1fce..d11397e 100644 --- a/ch03/README.md +++ b/ch03/README.md @@ -359,7 +359,7 @@ Network ordered integer addr: 0x4f7ce87f ```c #include char *inet_ntoa(struct in_addr adr); -//成功时返回保存转换结果的字符串地址值,失败时返回-1 +//成功时返回保存转换结果的字符串地址值,失败时返回 NULL 空指针 ``` 该函数将通过参数传入的整数型IP地址转换为字符串格式并返回。但要小心,返回值为 char 指针,返回字符串地址意味着字符串已经保存在内存空间,但是该函数未向程序员要求分配内存,而是再内部申请了内存保存了字符串。也就是说调用了该函数后要立即把信息复制到其他内存空间。因为,若再次调用 inet_ntoa 函数,则有可能覆盖之前保存的字符串信息。总之,再次调用 inet_ntoa 函数前返回的字符串地址是有效的。若需要长期保存,则应该将字符串复制到其他内存空间。 From 3ac4736611ea68d5950e8cc54252250373982029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8A=E5=AE=98=E6=B0=B8=E7=9F=B3?= <841842619@qq.com> Date: Mon, 4 Jul 2022 20:20:18 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20ch04=20=E9=83=A8?= =?UTF-8?q?=E5=88=86=E8=A1=A8=E8=BF=B0=20&=20=E4=BF=AE=E6=94=B9=E9=94=99?= =?UTF-8?q?=E5=88=AB=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch04/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ch04/README.md b/ch04/README.md index 0f1a096..4398fc3 100644 --- a/ch04/README.md +++ b/ch04/README.md @@ -116,7 +116,7 @@ addrlen: 第二个结构体参数 servaddr 变量的字节长度 客户端调用 connect 函数后,发生以下函数之一才会返回(完成函数调用): - 服务端接受连接请求 -- 发生断网等一场状况而中断连接请求 +- 发生断网等异常状况而中断连接请求 注意:**接受连接**不代表服务端调用 accept 函数,其实只是服务器端把连接请求信息记录到等待队列。因此 connect 函数返回后并不应该立即进行数据交换。 @@ -132,7 +132,7 @@ addrlen: 第二个结构体参数 servaddr 变量的字节长度 2. 结构体变量 serv_addr 中初始化IP和端口信息。初始化值为目标服务器端套接字的IP和端口信息。 3. 调用 connect 函数向服务端发起连接请求 4. 完成连接后,接收服务端传输的数据 -5. 接收数据后调用 close 函数关闭套接字,结束与服务器端的连接。 +5. 接收数据后调用 close 函数关闭套接字,结束与服务器端的连接。(对套接字调用close函数,对应于向建立连接的对应套接字发送EOF。即,如果客户端的套接字调用了close函数,服务端read时候会返回0。) #### 4.2.7 基于 TCP 的服务端/客户端函数调用关系 From 88b459b74b9f6fa2a7e1ec6863d289a9abb24476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8A=E5=AE=98=E6=B0=B8=E7=9F=B3?= <841842619@qq.com> Date: Mon, 4 Jul 2022 20:21:03 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20ch05=20=E9=94=99?= =?UTF-8?q?=E5=88=AB=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch05/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ch05/README.md b/ch05/README.md index aad1835..cd19cc2 100644 --- a/ch05/README.md +++ b/ch05/README.md @@ -22,7 +22,7 @@ write(sock, message, strlen(message)); str_len = read(sock, message, BUF_SIZE - 1); ``` -二者都在村换调用 read 和 write 函数。实际上之前的回声客户端将 100% 接受字节传输的数据,只不过接受数据时的单位有些问题。扩展客户端代码回顾范围,下面是,客户端的代码: +二者都在循环调用 read 和 write 函数。实际上之前的回声客户端将 100% 接受字节传输的数据,只不过接收数据时的单位有些问题。扩展客户端代码回顾范围,下面是,客户端的代码: ```c while (1) @@ -52,7 +52,7 @@ while (1) #### 5.1.3 如果问题不在于回声客户端:定义应用层协议 -回声客户端可以提前知道接收数据的长度,这在大多数情况下是不可能的。那么此时无法预知接收数据长度时应该如何手法数据?这是需要的是**应用层协议**的定义。在收发过程中定好规则(协议)以表示数据边界,或者提前告知需要发送的数据的大小。服务端/客户端实现过程中逐步定义的规则集合就是应用层协议。 +回声客户端可以提前知道接收数据的长度,这在大多数情况下是不可能的。那么此时无法预知接收数据长度时应该如何收发数据?这时需要的是**应用层协议**的定义。在收发过程中定好规则(协议)以表示数据边界,或者提前告知需要发送的数据的大小。服务端/客户端实现过程中逐步定义的规则集合就是应用层协议。 现在写一个小程序来体验应用层协议的定义过程。要求: @@ -83,7 +83,7 @@ gcc My_op_server.c -o myserver ![](https://i.loli.net/2019/01/15/5c3d966b81c03.png) -其实主要是对程序的一点点小改动,只需要再客户端固定好发送的格式,服务端按照固定格式解析,然后返回结果即可。 +其实主要是对程序的一点点小改动,只需要在客户端固定好发送的格式,服务端按照固定格式解析,然后返回结果即可。 书上的实现: @@ -182,7 +182,7 @@ TCP 在实际通信中也会经过三次对话过程,因此,该过程又被 对于主机 A 首次传输的数据包的确认消息(ACK 1001)和为主机 B 传输数据做准备的同步消息(SEQ 2000)捆绑发送。因此,此种类消息又称为 SYN+ACK。 -收发数据前向数据包分配序号,并向对方通报此序号,这都是为了防止数据丢失做的准备。通过项数据包分配序号并确认,可以在数据包丢失时马上查看并重传丢失的数据包。因此 TCP 可以保证可靠的数据传输。 +收发数据前向数据包分配序号,并向对方通报此序号,这都是为了防止数据丢失做的准备。通过向数据包分配序号并确认,可以在数据包丢失时马上查看并重传丢失的数据包。因此 TCP 可以保证可靠的数据传输。 通过这三个过程,这样主机 A 和主机 B 就确认了彼此已经准备就绪。 @@ -200,7 +200,7 @@ TCP 在实际通信中也会经过三次对话过程,因此,该过程又被 与三次握手协议相同,最后 + 1 是为了告知对方下次要传递的 SEQ 号。下面分析传输过程中数据包丢失的情况: -![](https://i.loli.net/2019/01/16/5c3ed371187a6.png)' +![](https://i.loli.net/2019/01/16/5c3ed371187a6.png) 上图表示了通过 SEQ 1301 数据包向主机 B 传递 100 字节数据。但中间发生了错误,主机 B 未收到,经过一段时间后,主机 A 仍然未收到对于 SEQ 1301 的 ACK 的确认,因此试着重传该数据包。为了完成该数据包的重传,TCP 套接字启动计时器以等待 ACK 应答。若相应计时器发生超时(Time-out!)则重传。