客户接受到三次握手的第二个分节时,connect返回,而服务器要知道接受到三路握手的第三个分节才返回,即在connect返回之后再过一半RTT才返回。
---
对于一条正常的连接,如果客户端输入EOF(Control-D)以终止客户,会引发底层发送FIN,那么一般情况下服务器会马上返回FIN+ACK,然后客户端发送ACK,然后该连接就会进入TIME_WAIT状态(2MSL等待)
---
慢系统调用:可能永远阻塞的系统调用。永远阻塞的系统调用是指调用有可能永远无法返回,多数网络支持函数都属于这一类。如,如果没有客户连接到服务器上,那么服务器的accept调用就没有返回的保证。
适用于慢系统调用的基本规则是:当阻塞于某个慢系统调用的一个进程捕获某个信号且相应信号处理函数返回时,该系统调用可能返回一个fEINTR错误。有
些内核自动重启某些被中断的系统调用。不过为了便于移植,当编写捕获信号的程序时,必须对慢系统调用返回EINTR有所准备。
---
wait和waitpid问题
场
景:如果客户与服务端建立5条连接,但是只对第一个进行读写,那么当在客户的第一个连接上向服务端发送EOF然后客户程序推出,会引起5个连接几乎同时终
止,引发了5个FIN,他们反过来使服务器的5个子进程基本在同一时刻终止。这又导致差不多在同一时刻有5个SIGCHLD信号递交给父进程。建立一个信
号处理函数并在其中调用wait并不足以防止出现僵尸进程。
问题:本问题在于,所有5个信号都在信号处理函数执行之前产生,而信号处理函数只执行一次,因为Unix信号一般不是排队的。更严重的是,本问题是不确定的,信号处理函数执行的次数是不确定的。
解决:信号处理函数中,我们在一个循环内调用waitpid,以获取所有已终止子进程的状态。必须制定WNOHANG选项,它告知waitpid在尚有终止的子进程在运行时不要阻塞。能在循环内调用wait,因为没有办法防止wait在正运行的子进程尚有未终止时阻塞。
---
accept返回前连接终止
三路握手完成从而连接建立以后,客户TCP却发送了一个RST(复位)。在服务器端看来,就在该连接已由TCP排队,等着服务器进程调用accept的时候RST到达,稍后,服务器进程调用accept。
情景模拟:启动服务器,让它调用socket、bind和listen然后在调用accept之前睡眠一小段时间。在服务器进程睡眠时,启动客户,让它调
用socket和connect。一旦connect返回,就设置SO_LINGER套结字选项以产生这个RST,然后终止。
源自berkeley的实现完全在内核中处理终止的连接,服务器进程根本看不到。大多数SVR4会返回一个错误给服务器进程,作为accept的返回结
果。这些SVR4实现返回一个EPROTO errno值,而POSIX指出返回的errno值必须是ECONNABORTED。
---
服务器进程终止
场景:阻塞客户进程(比如使其阻塞在从终端读入),然后kill掉服务端该连接对应的进程,这样服务端给客户发了FIN,客户响应ACK,但是尚未发送FIN。
---
对已经收到RST的连接发数据
当
一个进程向某个已收到RST的套结字执行写操作时,内核向该进程发送一个SIGPIPE信号。该信号的默认行为是终止进程,因此进程必须捕获它以免不情愿
地被终止。不论该进程是捕获了该信号并从信号处理函数返回,还是简单地忽略该信号,写操作都将返回EPIPE错误。
---
服务器主机崩溃
对read函数设置一个超时时间,使尽快发现连接已经出现故障。
---
服务器主机崩溃后重启
(1)启动服务器和客户,并在客户键入一行文本以确认连接已经建立
(2)服务器主机崩溃并重启
(3)在客户上键入一行文本,它将作为一个TCP数据分节发送到服务器主机
(4)当服务器主机崩溃后重启时,它的TCP丢失了崩溃前的所有连接信息,因此服务器TCP对于所收到的来自客户的数据分节响应以一个RST
(5)当客户TCP收到该RST时,客户正阻塞于readline调用,导致该调用返回ECONNREST错误。
---
服务器主机关机
Unix系统关机时,init进程通常先给所有进程发送SIGTERM信号(可以被捕获),等待一段固定的时间(通常5~20s),然后给所有仍在运行的
进程发送SIGKILL信号(不能被捕获)。这么做留给所有运行的进程一小段时间来清除和终止。如果不捕获SIGTERM信号并终止,服务器将由
SIGKILL信号终止。当服务器子进程终止时,它的所有打开着的描述符都被关闭。
阅读(1508) | 评论(0) | 转发(0) |