一、问题背景
最近项目中安装部署遇到一个非常有趣的问题,用ansible对一批服务器安装某个服务时,有个别服务启动失败,查看日志,报错显示“port already in use”。
二、问题分析
你可以能会说:
1. 是不是这组件你已经安装过了,端口已经监听了
2. 是不是其他程序已经占用了这个端口
经排查确认,确实是第二种,但是又有点特殊:这个端口被占用,不是作为服务端监听端口被占用,而是被某个程序作为客户端向内核注册申请的一个临时端口,跟其他程序通讯在使用。
这就引入我们接下来要谈论的一个知识点——socket。
SOCKET = IP + PORT
在网间网内部,每一个Socket用一个半相关描述:(协议,本地地址,本地端口)
一个完整的Socket有一个本地唯一的Socket号,由操作系统分配
AF_UNIX,同一主机的不同进程间通信,不经TCP/IP协议栈,内核直接转发,提高效率.。
# ss -tan | grep 22
# netstat -pantu | grep 22
目标机器的某个程序临时向内核注册了一个 大于 1024 的 tcp 的随机端口,正用于个其他服务端通讯
查看端口被哪个程序占用:
# lsof -i:${port}
# lsof -i:22
假设你要访问 https://www.example.com:443
User-Agent(一般是指浏览器)会向内核申请注册一个随机端口(1024< 端口 < 65535)向服务器的WEB程序(常用的有httpd,nginx等)443端口发起TCP的连接请求。
这个连接请求(原始的http请求经过TCP/IP4层模型的层层封包)到达服务器端后(这中间通过各种路由设备,局域网内除外),进入到网卡,然后是进入到内核的TCP/IP协议栈(用于识别该连接请求,解封包,一层一层的剥开),还有可能要经过Netfilter防火墙(属于内核的模块)的过滤,最终到达WEB程序(本文就以Nginx为例),最终建立了TCP/IP的连接。
解决方式:
1. 如果确认此进程不影响,可以杀掉
2. 等待程序结束,内核释放此端口
三、参考
socket(2) — Linux manual page
https://man7.org/linux/man-pages/man2/socket.2.html
一次完整的浏览器请求流程
https://www.jianshu.com/p/fbe0e9fa45a6
浏览器HTTP请求全过程
https://blog.csdn.net/lsyz0021/article/details/98850217