手把手写C++服务器(12):TCP自连接原理Python示例解决方案
Posted 沉迷单车的追风少年
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手把手写C++服务器(12):TCP自连接原理Python示例解决方案相关的知识,希望对你有一定的参考价值。
前言:《手把手写C++服务器》系列的第一篇文章:手把手写C++服务器(1):网络编程常见误区,当中就讲解了TCP自连接是网络编程常见的误区之一。这篇blog进一步讨论TCP自连接问题,并给出Python实例代码,以及这类问题的解决方案。
目录
什么是TCP自连接问题?
自连接就是自己连接自己的现象。当我们去连接一个正在监听的端口时,系统自动为我们分配一个临时端口去进行连接,这样就有可能分配到正在监听的端口号,然后出现自己连接自己的问题。
为什么说是坑?
因为当没意识到出现TCP自连接的时候,很难找到端口被占用的真正原因,给问题定位带来困难。具体的解决方法很简单。
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
如何解决TCP自连接问题?
断开连接重试即可。
Python3程序示例
#!/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多线程服务端编程》
以上是关于手把手写C++服务器(12):TCP自连接原理Python示例解决方案的主要内容,如果未能解决你的问题,请参考以下文章
手把手写C++服务器(18):TCP紧急传输的方法——带外数据 (原理与代码示例)
手把手写C++服务器(24):socket响应一般框架TCP修改缓冲区内核监听listen最大长度
手把手写C++服务器(14):基于UDP测量两台机器之间的网络延迟