socket需要由物理链路来传输,而这会导致很多的异常情况,下面对几种异常情况做下笔记。
建立连接会有3个包,分别为syn, syn ack, ack,当中某个包丢失都会导致建立连接失败。
下面列一下正常状态迁移:
c端首先发送syn
c None->SYN_SEND (send syn)
s端收到了syn包后,转为SYN_RECV
,同时发送syn ack。在这儿,s端会把该连接放入backlog。backlog主要是防止大量建立半连接导致服务端无法服务正常连接的攻击的。
s None->SYN_RECV (recv syn, send syn ack)
c端收到了syn ack后,会转为established状态,该半连接已经建立,同时发送ack回s端。
c SYN_SEND->ESTABLISHED (recv syn ack, send ack)
s端收到了ack后,该连接已建立,转为established状态,同时放入accept-queue处理。当accept-queue满了后,会拒绝连接。
s SYN_RECV->ESTABLISHED (recv ack)
在这种情况下,s端会返回一个rst (Connection refused)
可能会返回网络不可达,也可能会超时。在超时前由于syc发出而没有回应,会不断的重发,直到到达某个尝试次数,然后返回超时。
1) syn丢失。在这个情况下,底层协议会不断的重发syn,直到返回超时或者不可达。
2) syn ack丢失。在这个情况下,主动连接一方由于没有收到syn ack,会不断的重发syn包,这个和1)相似。对于s端,由于已经收到了syn包,所以处于syn_recv
状态,不断的回syn ack,会导致资源消耗。
3) ack丢失。在这个情况下,由于c端已经处于了established
状态,所以理论上已经可以使用send来发包了。然而s端还处于syn_recv
状态,在这段时间内,s端会不断的重发syn ack。c端发包后,由于s端不处于established状态,所以该包是发不到s端的,于是在底层协议的实现里,c端的发包会不断的重试,