前言:《手把手写C++服务器》系列的第一篇文章:手把手写C++服务器(1):网络编程常见误区,当中就讲解了TCP自连接是网络编程常见的误区之一。这篇blog进一步讨论TCP自连接问题,并给出Python实例代码,以及这类问题的解决方案。
目录
什么是TCP自连接问题?
为什么说是坑?
TCP自连接带来的危害?
选择端口的范围
查看端口号
如何解决TCP自连接问题?
Python3程序示例
参考
自连接就是自己连接自己的现象。当我们去连接一个正在监听的端口时,系统自动为我们分配一个临时端口去进行连接,这样就有可能分配到正在监听的端口号,然后出现自己连接自己的问题。
因为当没意识到出现TCP自连接的时候,很难找到端口被占用的真正原因,给问题定位带来困难。具体的解决方法很简单。
当程序去connect一个不处于监听的端口时,必然期待其连接失败,如果自连接出现,就意味着该端口被占用了,那么:
使用命令: sysctl -A |grep local_port_range
sysctl -A |grep local_port_range sysctl: reading key "kernel.unprivileged_userns_apparmor_policy" net.ipv4.ip_local_port_range = 32768 60999 sysctl: reading key "net.ipv6.conf.all.stable_secret" sysctl: reading key "net.ipv6.conf.default.stable_secret" sysctl: reading key "net.ipv6.conf.eth0.stable_secret" sysctl: reading key "net.ipv6.conf.lo.stable_secret"
端口号的范围是32768到60999之间
使用命令:nestat -ln
可以看到部署服务器的时候,为了安全仅仅开放了一个端口号22
断开连接重试即可。
#!/usr/bin/python3 import errno import socket import sys import time if len(sys.argv) < 2: print("Usage: %s port" % sys.argv[0]) print("port should in net.ipv4.ip_local_port_range") else: port = int(sys.argv[1]) for i in range(65536): try: sock = socket.create_connection(('localhost', port)) print("connected", sock.getsockname(), sock.getpeername()) time.sleep(60*60) except socket.error as e: if e.errno != errno.ECONNREFUSED: print("socket error!") break print("end!")
运行后,TCP在net.ipv4.ip_local_port_range范围内选择一个端口号连接服务器端口,如果这时候我们指定的端口号正好和自身的端口号相连就会出现TCP自连接问题了。
运行命令:
python self-connect-python3.py 22
我们这里会不会出现自连接问题呢?
答案是不会的。因为为了安全,我的服务器现在只打开了22这一个端口,而我TCP的端口号范围是[32768,60999]之间,两者没有交集。因此,服务器用几个端口就开放几个端口,是一种非常好的运维习惯。
参考
- https://xduwq.blog.csdn.net/article/details/117190817
- 《linux高性能服务器编程》
- 《linux多线程服务端编程》