mirror of
https://github.com/riba2534/TCP-IP-NetworkNote.git
synced 2026-06-30 09:56:04 +08:00
docs: 全面校对全部章节文档与示例代码
通过多智能体工作流对 19 章笔记(README.md)与 96 个 .c 示例代码做深度 审查与对抗性验证,修复 317 处确认问题,涵盖: 技术正确性: - 修复缓冲区溢出:echo_mpserv.c / echo_storeserv.c 等的 read(buf, BUFSIZ) 改为 BUF_SIZE(buf 仅 30 字节,BUFSIZ 远大于此) - 修复 open() 缺少 mode 参数:low_open.c / fd_seri.c / desto.c 等 O_CREAT 调用补 0644(原导致 low_read 链路失败) - 修复 feof 循环 off-by-one:news_sender.c / echo_stdserv.c 改用 fgets 返回值判断 - 修复线程竞态:chat_server.c / webserv_linux.c 的 &clnt_sock 栈地址 传子线程改为 malloc 分配 + free - 修复索引混淆:char_EPLTserv.c 错用 clnt_sock 查找改为 ep_events[i].data.fd - 修复格式化符:thread4.c 的 sizeof 用 %d 改为 %zu - 修正习题答案:ch01 fd 序号、ch13 MSG_OOB 加粗项、ch09 Nagle 等 文档规范: - 统一术语:IPv4/IPv6、接收(receive)/连接(connection) - 修正错别字:occured→occurred、cooffee→coffee、Usgae→Usage、 eerror→error、proess→process 等 - 修复病句、补全习题答案解释 - GitHub 绝对 URL 改为相对路径,统一项目引用规范 - 同步根 README.md(前言 + 19 章合并) 另:重命名 ch10/remove_zomebie.c → remove_zombie.c(修正拼写) 所有 .c 文件经 gcc 编译验证通过(ch17 epoll 文件因 macOS 无 sys/epoll.h 跳过,已人工复核)。
This commit is contained in:
@@ -39,7 +39,7 @@ I/O 复用技术可以解决这个问题。
|
||||
|
||||
> 「好像不能同时说话?」
|
||||
|
||||
实际上,因为是在进行对话,所以很少发生同时说话的情况。也就是说,上述系统采用的是**「时分复用」**技术。因为说话人声频率不同,即使在同时说话也能进行一定程度上的区分(杂音也随之增多)。因此,也可以说是「频分复用技术」。
|
||||
实际上,因为是在进行对话,所以很少发生同时说话的情况。也就是说,上述系统采用的是**「时分复用」**技术。因为说话人的声音频率不同,即使在同时说话也能进行一定程度上的区分(杂音也随之增多)。因此,也可以说是「频分复用技术」。
|
||||
|
||||
#### 12.1.3 复用技术在服务器端的应用
|
||||
|
||||
@@ -67,7 +67,7 @@ select 函数是最具代表性的实现复用服务器的方法。在 Windows
|
||||
|
||||
> 术语:「事件」。当发生监视项对应情况时,称「发生了事件」。
|
||||
|
||||
select 函数的使用方法与一般函数的区别并不大,更准确的说,他很难使用。但是为了实现 I/O 复用服务器端,我们应该掌握 select 函数,并运用于套接字编程当中。认为「select 函数是 I/O 复用的全部内容」也并不为过。select 函数的调用过程如下图所示:
|
||||
select 函数的使用方法与一般函数的区别并不大,更准确地说,它很难使用。但是为了实现 I/O 复用服务器端,我们应该掌握 select 函数,并运用于套接字编程当中。认为「select 函数是 I/O 复用的全部内容」也并不为过。select 函数的调用过程如下图所示:
|
||||
|
||||

|
||||
|
||||
@@ -116,7 +116,7 @@ timeout: 调用 select 函数后,为防止陷入无限阻塞的状态,传递
|
||||
1. 文件描述符的监视(检查)范围是?
|
||||
2. 如何设定 select 函数的超时时间?
|
||||
|
||||
第一,文件描述符的监视范围和 select 的第一个参数有关。实际上,select 函数要求通过第一个参数传递监视对象文件描述符的数量。因此,需要得到注册在 fd_set 变量中的文件描述符数。但每次新建文件描述符时,其值就会增加 1 ,故只需将最大的文件描述符值加 1 再传递给 select 函数即可。加 1 是因为文件描述符的值是从 0 开始的。
|
||||
第一,文件描述符的监视范围和 select 的第一个参数有关。实际上,select 函数要求通过第一个参数传递监视对象文件描述符的数量。因此,需要得到注册在 fd_set 变量中的文件描述符数。但文件描述符的值通常随创建而增大(已关闭的描述符可能被系统复用),故只需将最大的文件描述符值加 1 再传递给 select 函数即可。加 1 是因为文件描述符的值是从 0 开始的。
|
||||
|
||||
第二,select 函数的超时时间与 select 函数的最后一个参数有关,其中 timeval 结构体定义如下:
|
||||
|
||||
@@ -142,7 +142,7 @@ select 返回正整数时,怎样获知哪些文件描述符发生了变化?
|
||||
|
||||
下面是一个 select 函数的例子:
|
||||
|
||||
- [select.c](https://github.com/riba2534/TCP-IP-NetworkNote/blob/master/ch12/select.c)
|
||||
- [select.c](select.c)
|
||||
|
||||
编译运行:
|
||||
|
||||
@@ -161,7 +161,7 @@ gcc select.c -o select
|
||||
|
||||
下面通过 select 函数实现 I/O 复用服务器端。下面是基于 I/O 复用的回声服务器端。
|
||||
|
||||
- [echo_selectserv.c](https://github.com/riba2534/TCP-IP-NetworkNote/blob/master/ch12/echo_selectserv.c)
|
||||
- [echo_selectserv.c](echo_selectserv.c)
|
||||
|
||||
编译运行:
|
||||
|
||||
@@ -196,6 +196,11 @@ gcc echo_selectserv.c -o selserv
|
||||
|
||||
3. **复用服务器端需要 select 函数。下列关于 select 函数使用方法的描述错误的是?**
|
||||
|
||||
① 调用 select 函数前需要集中待监视的文件描述符。
|
||||
② 调用 select 函数后无需再次注册监视对象。
|
||||
③ 复用服务器端无法同时向多个客户端提供服务。
|
||||
④ 基于 select 的复用服务器只需要 1 个进程,可减少创建多进程带来的负担。
|
||||
|
||||
答:错误的描述是 2 和 3。说明如下:
|
||||
|
||||
- 描述 1 正确:调用 select 函数前需要集中 I/O 监视对象的文件描述符。
|
||||
|
||||
@@ -59,6 +59,8 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
adr_sz = sizeof(clnt_adr);
|
||||
clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_adr, &adr_sz);
|
||||
if (clnt_sock == -1)
|
||||
continue;
|
||||
|
||||
FD_SET(clnt_sock, &reads); //注册一个clnt_sock
|
||||
if (fd_max < clnt_sock)
|
||||
@@ -68,7 +70,13 @@ int main(int argc, char *argv[])
|
||||
else //不是服务端套接字时
|
||||
{
|
||||
str_len = read(i, buf, BUF_SIZE); //i指的是当前发起请求的客户端
|
||||
if (str_len == 0)
|
||||
if (str_len == -1)
|
||||
{
|
||||
FD_CLR(i, &reads);
|
||||
close(i);
|
||||
printf("closed client(read error): %d \n", i);
|
||||
}
|
||||
else if (str_len == 0)
|
||||
{
|
||||
FD_CLR(i, &reads);
|
||||
close(i);
|
||||
|
||||
@@ -39,6 +39,11 @@ int main(int argc, char *argv[])
|
||||
if (FD_ISSET(0, &temps)) //验证发生变化的值是否是标准输入端
|
||||
{
|
||||
str_len = read(0, buf, BUF_SIZE);
|
||||
if (str_len == -1)
|
||||
{
|
||||
puts("read error!");
|
||||
continue;
|
||||
}
|
||||
buf[str_len] = 0;
|
||||
printf("message from console: %s", buf);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user