UNIX网络编程---TCP客户/服务器程序示例(五)
一、概述
下面的简单的例子是执行如下步骤的一个回射服务器:
1)客户从标准输入读入一行文本,并写给服务器
2)服务器从网络输入读入这行文本,并回射给客户
3)客户从网络输入读入这行回射文本,并显示在标准输出上

在客户和服务器之间画了两个箭头,不过他们实际上构成一个全双工的TCP链接。fgets和fputs这两个函数来自标注I/O函数库,writen和readline这两个函数是在3.9有讲解,这里使用的都是基本的函数read和write.
还需要考虑很多边界条件:客户和服务器启动时发送什么?客户正常终止时发生什么?若服务器进程在客户之前终止,则客户会发生什么?若服务器主机崩溃,则客户发生什么?
这里给了函数简单的main的实现
这种情况一般被忽略,直接再次调用accept即可,在16.6节我们将再次回到这些中止的链接,查看在与select函数和正常阻塞模式下的监听套接字组合时他们是如何成为问题的。
十二、服务器进程终止在服务器启动以后,客户也正常启动,然后在客户端输入一行,在这个时候杀死服务器子进程,看有什么效果。
1))在同一主机上启动服务器和客户,并在客户上键入一行文本,以验证一切正常。正常情况下文本由服务器子进程回射给客户。
2)找到服务器子进程的进程ID,并执行kill命令杀死它,作为进程终止处理的部分工作,子进程中所有打开着的描述符都被关闭。这就导致向客户发送一个FIN,而客户TCP则响应以一个ACK。这就是TCP连接终止工作的前半部分。
3)SIGCHLD信号被发送给服务器父进程,并得到正确处理。
4)客户上没有发送任何特殊之事。客户TCP接受来自服务器TCP的FIN并响应以一个ACK,然而问题是客户进程阻塞在fgets上,等到从终端接受一行文本。
5)此时,在另外一个窗口上运行netstat命令,以观察套接字的状态。可以发现有两个相关的进程(子进程被kill),其中一个进程处于LISTEN状态,一个处于FIN_WAIT2状态,一个处于CLOSE_WAIT状态,可以看到TCP连接终止序列的前半部分已经完成。
6)我们可以在客户上再键入一行文本,以下是从第一步的动作
当我们键入”another line“字符串时,str_cli调用write,客户tcp接着把数据发送给服务器、TCP允许这么做,因为客户TCP接受到FIN只是表示服务器进程已关闭了链接的服务器端,从而不再往其中发送任何数据而已、FIN的接受并没有告知客户TCP服务器进程已经终止(在这里确实终止了)在6.6节讨论TCP的半关闭时我们再讨论这一点。
7)当服务器TCP接受到来自客户的数据时,既然先前打开那个套接字的进程已经终止,于是响应一个RST。通过使用tcpdump来观察分组,RST确实发送了。然而客户进程看不到这个RST,因为它在调用write后立即调用read,并且由于又接受到了客户的FIN,所调用的read立即返回0,我们的客户此时并为期望收到EOF。
8)当客户终止时,它所打开的描述符都被关闭。
本例子的问题在于,当FIN到达套,而是应该阻塞在其中任何一个套接字时,客户正阻塞在fgets调用上。客户实际上再应对两个描述符------套接字和用户输入,它不能单纯阻塞在这两个源中某个特定源的输入上(正如目前编写的str-cli函数所为),而是应该阻塞在其中任何一个源的输入上,事实上这正是select和poll这两个函数的目的之一,在重写的stl_cli函数之后,一旦杀死服务器子进程,客户就会立即被告知已收到FIN。
十三、sigpipe信号要是客户部例会read函数返回的错误,反而写入更多的数据到服务器上,那么会发生什么呢?
适用于此的规则是:当一个进程向某个已收到RST的套接字执行写操作时,内核向该进程发送一个SIGPIPE信号。该信号的默认行为是终止进程,因此进程必须捕获它以免不情愿地被终止。
十四、服务器主机崩溃在不同的主机上运行服务器和客户,键入一行确认正常工作。
1)当服务器主机崩溃时,已有的网络连接上不发出任何东西,这里我们假设的是主机崩溃,而不是由操作员执行命令关机
2)我们在客户上键入一行文本,write写入到内核,再由客户TCP作为一个数据分节送出。客户随后阻塞与read调用,等待回射的应答。
3)如果我们用tcpdump观察网络就会发现,客户TCP储蓄重传数据分节,试图从服务器上接受一个ACK。重传了很久很久,当客户TCP最终放弃是(假设这段时间内主机没有重新启动),给客户进程返回一个错误。既然客户阻塞在read调用上,该调用将返回一个错误。假设服务器主机已崩溃,从而对客户的数据分节根本没有响应,那么返回的错误是ETIMEDOUT。然而如果某个中间路由器判定服务器主机已经不可达,从而响应一个”destination unreachable“的ICMP消息。
如果我们不主动向它发生数据也想检测出服务器主机的崩溃,那么需要采用另外一个技术,也就是我们在7.5节讨论的SO_KEEPALIVE套接字选项。
十五、服务器主机崩溃后重启十六、 服务器主机关机十七、 Tcp程序例子小结十八、 数据格式