1.connect函数调用会激发TCP三路握手协议,调用失败返回以下三种情况:
1.TCP客户端没有收到SYN分节,返回ETIMEOUT错误。如果发送一个SYN分节,等待6s没有响应,再发送一个,等待24s没有响应,再发送一个,等待75s没有响应就返回本 错误。
2.如果对客户端SYN的响应是RST(表示复位),则表示该服务器主机没有进程在等待与之连接(1.服务器上没有监听套接字,2.服务器主动取消了与客户端的连接,3.接收到一个不存在的连接上的分节),返回ECONNREFUSED(硬错误)
3.如果客户端发出的SYN分节在中间某个路由器返回“destination unreachable”,持续发出SYN分节,75S后仍热未收到响应,返回EHOSTUNREACH 或者ENETUNREANCH
2.listen(int sockfd, int backlog);socket套接字建立时,默认是主动连接,调用了listen函数后由主动连接变为被动,指示内核应接收指向该套接字的连接,套接字状态由CLOSED 变为LISTEN状态。
内核为sockfd指向的套接字维护两个队列。一个未完成队列(incomplete connection dequeue),一个已完成队列(completed connection dequeue),两个队列之和等于backlog值。每当connect函数发起syn包时,系统在未完成队列创建一个新项然后响应三路握手的第二个分节,服务器的syn响应,同时捎带客户端的syn的ack,这个新建项一直保存到第三个分节到达或者超时。如果三路握手完成,就从未完成队列移到已完成队列队尾,当进程调用accpet时,把已完成队列的对头返回给进程,出于未完成队列的项状态为SYNC_RECVED,已完成队列的状态为ESTABLISHED。
3.close()函数会使套接字描述符引用计数减一,shutdown()产生一些列的Fin终止连接。
4.
1.TCP连接的建立
状 态 |
描 述 |
CLOSED |
关闭状态,没有连接活动或正在进行 |
LISTEN |
监听状态,服务器正在等待连接进入 |
SYN RCVD |
收到一个连接请求,尚未确认 |
SYN SENT |
已经发出连接请求,等待确认 |
ESTABLISHED |
连接建立,正常数据传输状态 |
FIN WAIT 1 |
(主动关闭)已经发送关闭请求,等待确认 |
FIN WAIT 2 |
(主动关闭)收到对方关闭确认,等待对方关闭请求 |
TIMED WAIT |
完成双向关闭,等待所有分组死掉 |
CLOSING |
双方同时尝试关闭,等待对方确认 |
CLOSE WAIT |
(被动关闭)收到对方关闭请求,已经确认 |
LAST ACK |
(被动关闭)等待最后一个关闭确认,并等待所有分组死掉 |
TCP建立与释放的变迁如图所示:
5.Accept函数返回前连接终止
三路握手完成连接建立后,客户端却发来一个RST(复位),在服务器端看来,就在连接该由TCP排队,等着服务器进程调用Accept时RST到达,Accept返回ECONNABORTED,这时服务器忽略就行,再次调用Accept函数。
6.服务器进程终止(进程崩溃)
服务器进程崩溃后,会首先发送Fin到客户端,客户端read()函数返回EOF,客户端返回ACK和SNC,由于服务器进程已经崩溃,客户端会收到RST消息,这时套接字变为可读,read()函数返回-1,errno里面有错误码。
7.服务器主机崩溃
客户端TCP持续重传分节,试图从服务器上获得一个ACK,会在9分钟内重传12次,然后放弃。在read()函数返回错误ETIMEOUT,如果中间路由器出了问题,会返回EHOSTUNREACH或者EHOSTUNREACH。如果在重传期间服务器重启了,这时服务器由于丢失了所有连接信息,返回一个RST,客户端收到后read()返回ECONNRESET错误。
8.close()与shutdown()不同
1.close()函数调用后,套接字引用计数减一,只有当引用计数为0时,才会关闭套接字。shutdown()不管套接字计数激发TCP正常连接终止序列。
2.close()读和写同时关闭,shutdown()可控。
9.socket选项 KeepAlive
给一个TCP选项设置保持存活后,如果2小时内在该套接字任一方都没有数据交换,TCP就自动给对端发送一个保持存活探测分节,这是一个对端必须响应的分节,会导致如下三种情况:
1.对端以期望的ack响应,在又经过无动静的2小时后,TCP发送另一个分节。
2.对端以RST响应,告知本端,对端已崩溃,返回错误ECONNRESET,套接字本身关闭。
3.对端对保持存活探测分节没有任何响应,TCP继续发送8个分节,11分15秒后放弃。
10.Linger