另外,0端口是系统的保留端口号,若bind时用了0端口,则表示由系统分配一个端口,该端口介于1024和5000之间。
在进行client不断的对server端进行connect的过程中发现下面这个syn_recv状态,而且循环6w次的链接只进行了2W多次就出错了。
Linux内核协议栈为一个tcp连接管理使用两个队列,一个是半链接队列(用来保存处于SYN_SENT和SYN_RECV状态的请求),一个是全连接队列(accpetd队列)(用来保存处于established状态,但是应用层没有调用accept取走的请求)。
其中全连接队列somaxconn的参数为1表示监听队列的总长度(实际可以完成somaxconn+1个连接的建立)
半连接队列tcp_max_syn_backlog为1(实际可以将tcp_max_syn_backlog+1个syn分节放入其中)
但是在应用层有 int listen(int sockfd, int backlog);。。。然后实际的全连接队列的长度限制是min(backlog, somaxconn);
默认的话半连接队列的长度是/proc/sys/net/ipv4/tcp_max_syn_backlog,默认是1024。如果开启了syncookies,那么基本上没有限制。
全连接队列的长度是/proc/sys/net/core/somaxconn,默认是128,表示最多有129个established链接等待accept。(为什么是129?详见下面的附录1)。
当全连接队列已满且半连接队列未满的情况下:
当客户端发起一个syn分节时,服务端不会丢弃该syn分节,而是直接响应ack和syn,这时客户端响应ack,并成为established状态,而服务端收到ack响应后,试图将该syn分节从半连接队列中移除,并加入全链接队列,然后由于全连接队列已经满了,这时,在默认情况下,服务端啥也不做,而且不会将该连接由SYN_RECV变成ESTABLISHED,服务端仅仅只是创建一个定时器,以固定间隔重传syn和ack到客户端,直到到达系统默认的synack重传阖值,然后服务端将处于半连接队列里面的syn分节丢弃。
当全连接已满且半连接队列也满的情况下:
当客户端发起一个syn分节时,服务端发现半连接队列已经满了,同时该syn分节尚未重传过,服务端直接丢弃该syn分节,然后客户端过了4秒重传syn分节,这个时候服务端发现半连接队列已满同时,该syn分节已经重传过了,服务端收下了该syn分节,并响应客户端syn+ack,客户端收到syn+ack后,响应ack。客户端三次握手已经完成,而服务端收到ack之后,发现全连接队列是满的,这个时候不会将该连接从SYN_RECV转换成ESTABLISHED,服务端创建定时器,定时重传syn+ack, 直到到达系统默认的synack重传阖值,然后服务端将处于半连接队列里面的syn分节丢弃
实际队列中的数量比max的数值大1,标号从0开始,直到max数值也能使用: