概述
1. 什么是自连接(self-connection)?
在发起连接时,TCP/IP的协议栈会先选择source IP和source port,在没有显示调用bind()的情况下,source IP由路由表确定,source port由TCP/IP协议栈从local port range中选取尚未使用的port。如果destination IP正好是本机,而destination port位于local port range,且没有服务器监听(listen)的话,source port可能正好选中了destination port,这就出现了**(source IP,source port)=(destination IP,destination port)**的情况,即发生了自连接。
2. 现象分析:
destination IP为本机比较好理解,例如服务器程序和客户端程序位于同一台电脑上。但为什么会出现source port = destination port的现象呢?
考虑tcp正常建立连接过程,首先svr要在b端口上listen,cli再使用a端口connect,客户端一般不显式bind,而由内核代为选取一个空闲端口号,那么,因为svr已将b端口占用,cli不管是用户bind还是内核选择,都不可能选到b(不妨试试,在svr已bind时,cli再使用这个端口是会报错的),这样看来,同一个端口自连接就是一个伪命题。
那如果svr没有绑定呢?考虑下面两种情况:
- 同时打开:svr和cli同时发送SYN,又分别回答ACK+SYN,双方收到对方的ACK后,两个TCP连接均正常建立。如图:
(注意,同时打开是TCP协议中明确表明的正确行为,即使它没有listen监听,而是双方都使用主动发送SYN来建立连接。)
在同时打开的情况下,就有可能出现source port = destination port的情况。例如:程序(svr或cli)向destport发送一个SYN,因为目的 IP是自己,因此会被loopback网络接口处理程序回送给本机TCP/IP协议栈,又因为port是自己,于是这个SYN送给了正在等SYN的自己,之后发送SYN+ACK,同样原理,这个报文又会会送给自己,于是连接建立。
- 本来正常运行的cli和svr,svr偶然挂掉之后,cli再去连接它,就有可能出现自连接现象。
同一台机器上的cli和svr建立了一个长连接,svr挂掉了,端口释放,cli去connect这个目的端口的时候正好选择了这个端口作为源端口,此时该端口没人用,使用是合法的,于是自连接形成了。
为什么svr程序崩溃后应用没有主动关闭连接呢?根据TCP协议,一个空闲的TCP连接,除非主动断开连接,否则连接一直维持。即使中间路由器崩溃,连接也存在,甚至对端主机崩溃,另一端也是不知道的,连接依然存在。(Linux的TCP实现默认不开启保活功能)
3. 自连接的解决办法:
首先要了解本机local port range的范围,在系统文件/etc/sysctl.conf的net.ip_local_port_range参数规定了该范围。我们只需要限定服务监听端口在该范围以外,就不会出现自连接现象了。
参考:
详解tcp端口自连接,成因及后果-腾讯游戏学院https://gameinstitute.qq.com/community/detail/112599
最后
以上就是无心香烟为你收集整理的TCP自连接的全部内容,希望文章能够帮你解决TCP自连接所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复