Skip to content

Latest commit

 

History

History
61 lines (43 loc) · 4.07 KB

File metadata and controls

61 lines (43 loc) · 4.07 KB

1.我们说过一个描述符集可以用 C 语言中的赋值语句赋给另一描述符集,如果描述符集是一个整形数组,那么这是怎么做到的?(提示:研究一下你自己系统中的 <sys/select.h> 或 <sys/types.h>)

  • 把数组包裹在结构体中,就可以直接赋值了。
  • 示例程序: Practise_01.c
  • 运行结果如下:
progs git:(master) ✗ cc Practise_01.c && ./a.out
  cccccccccc
  cccccccccc
  cccccccccc
  cccccccccc
  cccccccccc
  cccccccccc
  cccccccccc
  cccccccccc
  cccccccccc
  cccccccccc

2. 在 6.3 节中讨论 select 返回可写条件时,为什么必须限定套接字为非阻塞才可以说一次写操作将返回一个正值?

  • 如果套接字发送缓冲区低水位设置为 2048, 这表示至少要有 2048 字节可用空间,描述符才处于可写状态,如果一次性写 2048 字节,那么 write 立马返回。如果一次性写 2049 字节数据,应用进程会阻塞在 write 调用上,直到 2049 字节的发送缓冲区空闲空间可用。而对于 read 操作,只要接受缓冲区中数据大于低水位,就可以立马返回。而 write 有阻塞的风险。

3. 如果在图 6-9 的第 19 行上的 if 关键词前加上 else 关键词,将会发生什么?

if (FD_ISSET(sockfd, &rset)) {
		/* 从接收缓冲区读数据 */
		/* 写到标准输出 */
} else if (FD_ISSET(fileno(stdin), &rset) {
	   /* 从标准输入读数据 */
	   /* 将数据写到发送缓冲区 */
}
  • 这么做没有使客户端变得不可用,因为假如 select 返回两个描述符都可读,第一次因为第一个 if 判断为真,而跳过了 else if 中的代码,但是第二次迭代调用 select 上时,又会发现标准输入可读,因此会进入 else if 分支。

4. 在图 6-21 的例子中加上一段代码,使得服务器能够使用内核当前允许的最多描述符数。(提示:研究一下 setrlimit 函数)

  • 使用 getrlimit 函数获取 RLIMIT_NOFILE,即当前进程允许打开的最大文件个数的软限制和硬限制,然后把软限制的数量改成硬限制的数量。最后的改动调用 setrlimit 操作。
  • 示例程序 Practise_04.c

5. 让我们看看当 shutdown 的第二个参数为 SHUT_RD 时将发生什么。以图 5-4 中的 TCP 客户程序为基础并做如下改动:把端口号从 SERV_PORT 改为 19,也就是 chargen 服务器(图 2-18)所监听的端口;以调用 pause 取代调用 str_cli。指定本地局域网上运行 chargen 服务器的某个主机的 IP 地址来运行这个客户程序。以诸如 tcpdump 这类工具观察分组,看到发生了什么?

  • 使用 SHUT_WR 后,发送缓冲区中所有数据都被发出,后紧跟 FIN。不能对这样的描述符调用写函数。
  • 使用 SHUT_RD 后,接受缓冲区中现有数据都被丢弃,之后对端发来的数据都被确认,然后丢弃。不能对这样的描述符调用读函数。

6. 为什么应用程序会以参数 SHUT_RDWR 来调用 shutdown,而不是仅仅调用 close?

  • close 只有当文件描述符计数减为 0 才发送 FIN。而 shutdown 立刻发送 FIN。

7. 图 6-22 中当客户端发送一个 RST 来终止连接时,将会发生什么?

  • select 指示该描述符可读,然后在 Read 包裹函数中进程被终止,因为这是一个单进程服务器,因此整个服务器停止服务。但通常服务器不能这样脆弱,正确的处理方式是关闭连接,记录错误。

8. 重写图 6-25 中的代码,调用 sysconf 来确定描述符的最大数目,并相应地分配 client 数组。