您的位置:首页 > 理论基础 > 计算机网络

《UNIX网络编程卷1》读书笔记--第五章TCP客户/服务实例

2017-03-24 11:39 246 查看

前言

本章开始编写一个完整的TCP客户/服务器程序实例。
(1) 客户冲标准输入读入一行文本,并写给服务器
(2)服务器从网络输入读入这行文本,并回射给客户
(3)客户从网络读入这行回射文本,并显示在标准输出上。




(这个图是根据书中原图我重新绘制的图,可以看到服务器调用来了read而客户端调用readline,但是根据之前的讲诉,readline能够保证一次读取“全部”信息,还有书中后面关于str_echo函数的描述,我认为这里TCP服务器应该使用readline更加合理,尽管代码和图中给出的是read调用)

关注点

客户和服务器正常启动

防止僵尸进程的信号处理

服务器进程在客户之前终止,客户端情况

服务器主机崩溃,客户端情况

服务器主机崩溃后重启,客户端情况

客户和服务器正常启动与终止

如图所示,正常启动后客户端阻塞于fgets调用,服务器子进程阻塞与readline(read)调用,服务器父进程阻塞于accept调用。因此三个进程都处于睡眠状态。


正常终止:



防止僵尸进程的信号处理

如果父进程没有捕获子进程的SIGCHID信号,那么子进程将成为僵尸进程。


如何捕获?可以采用wait或者waitpid

#include <sys/wait.h>
pit_t wait(int *statloc);
pid_t waitpid(pid_t pid, in * staloc, int options);


当有父进程fork出多个子进程时,应该采用waitpid获得全部子进程pid来进行信号捕获。调用wait将产生不确定的后果。


遗留问题

服务器进程在客户之前终止,客户端情况

这里说的终止是区别于主机崩溃的终止,也就是说,终止前是有给客户端发送FIN的,服务器主机关机也跟这类终止相同。
但是虽然发送的FIN可以得到客户TCP的ACK回复,但是正阻塞在fgets调用的客户端程序却没有察觉,如果此时客户端输入并且将数据发送给对端,这时服务端会回复RST,为什么?因为这个和一般的终止连接不同,对端进程已经终止,没有进程能识别这个数据。
此时客户调用readline读取到刚开始的FIN,这时readline返回0,报告连接终止。
连接已经终止,但是如果我们此时没有终止进程,这时可能的,我们再继续往不存在的连接发送数据就会产生SIGPIPE信号(内核向应用进程发送),该信号的默认行为是终止进程,因此进程必须捕获它以免不情愿地被终止。


服务器主机崩溃,客户端情况

服务器主机崩溃,那么用户发送的数据将使得路由器相应一个destination unreachable的ICMP消息。客户端将会产生数次重传。处理这种问题可以有两种方法:
1.对readline调用设置一个更短的超时
2.采用SO_KEEPALIVE选项


服务器主机崩溃后重启,客户端情况

服务器重启后,它的TCP丢失了崩溃前的所有连接消息,因此服务器TCP对于所有收到的来自客户的数据分节响应一个RST。而此时客户正阻塞在readline调用,导致该调用返回ECONNRESET
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息