某系统启动通讯组件过程中,服务端组件启动报错“33801端口已被占用”,而作为服务端监听的端口集合本身无重复,通过查看连接发现,为客户端通过该端口建立的SOCKET连接。
客户端建立SOCKET连接的过程未指定端口,则由操作系统内核指定未被占用的端口,由于服务端组件监听启动在后,客户端连接启动在前,所以对应的服务端端口被提前分配给客户端使用,导致服务端无法建立监听。
既然问题已经明确,那接下来就是如何解决啦。首先,想出了方案一,既然服务端可以指定监听端口,那客户端是不是也可以指定连接的端口呢,只要我不使用服务端对应的端口,那问题就解决啦。然后就发现了如下代码:
原来不仅服务端可以使用bind方法,客户端也可以。感觉看到了希望的曙光,可是深入思考后发现了问题,在通讯组件中,尤其是SOCKET短连接的连接池,一笔交易就对应一个端口,如何管理这些可以使用的端口呢?结合连接池,瞬间想到了可以模仿设置一个端口号池,每次建联前从端口号池中获取一个端口号用于连接,小的问题就是,如果在高并发下,对应端口使用的过多,而连接断开后处于TIME_WAIT状态,该端口同样无法使用。。。。有了,我可以设置连接池先进先出呀,然后设置reuse参数,那么就能尽量避免端口处于不可用状态啦~
解决方案有了雏形后,总感觉自己跑偏了,回想使用的各个通讯框架和分布式服务框架,它们都没有对此进行处理,额,肯定有问题,而且通讯框架的底层应该是最基础的通讯方式,这种端口号的设计都已经到操作系统内核,完全超出了作用范围。
回到问题本身,就是服务端端口被客户端所占用,本身端口分配就是操作系统完成的,那么它是不是对应有什么处理呢?于是发现了新大陆
net.ipv4.ip_local_port_range 它指定了本地发起连接请求时可以获取的随机端口
ip_local_reserved_ports 它指定了本地预留的服务端监听端口,默认无
查看现在的测试环境,发现net.ipv4.ip_local_port_range没有进行修改,仍然采用默认
32768 61000,而出现问题的通讯组件所监听的33801端口正好在该范围内,于是豁然开朗
既然操作系统有解决方案,那通讯组件还是不插手啦~看来服务端的端口监听还是要注意选取范围呀。
参考来自:
https://www.cnblogs.com/gaoyuechen/p/7725336.html
https://blog.csdn.net/xygg0801/article/details/55195083
https://blog.csdn.net/afer198215/article/details/6834041