c00WKmdje2wZLrSI
V2EX  ›  Go 编程语言

求助, go 端口占用的问题

By c00WKmdje2wZLrSI at 2023 年 12 月 15 日 · 3641 次点击

环境:ubuntu22.04 go1.20

代码类似于

go func() {
		//开启 websocket 监听
		http.HandleFunc("/", s.handler)
		err := http.ListenAndServe("0.0.0.0:9999", nil)
		if err != nil {
			logger.Log.Fatal(fmt.Sprintf("err=%v", err))
		}
	}()

但是有时候启动会报错,显示err=listen tcp 0.0.0.0:9999: bind: address already in use 然而我使用netstat -tuln |grep 9999时,却显示这个端口没被占用

于是我写一个脚本

#!/bin/bash

while true; do
  netstat -tuln |grep 9999
  sleep 0.1
done

一直开着,再写一个守护脚本当 go 进程结束时自动重启 然后我发现 go 进程因为端口占用问题已经重启了几十次,但是端口扫描的脚本却一次显示端口被占用的情况都没有

但是当我过几个小时再次重启 go 进程时,端口占用问题又消失了 这到底是怎么一回事,而且这情况不是必现的,是偶尔会出现

33 条回复  •  2023-12-18 20:34:17 +08:00
c00WKmdje2wZLrSI
   1
c00WKmdje2wZLrSI  
OP
   2023 年 12 月 15 日
各位大哥有没有解决的思路可以说一说
misaka19000
   2
misaka19000  
   2023 年 12 月 15 日 via Android
写个其它语言的代码看看能不能监听这个端口
daniel8642
   3
daniel8642  
   2023 年 12 月 15 日
0.0.0.0:9999
可以试试填写一下需要绑定到的网卡 ip 地址。
之前在 wsl2 上出现绑定之后访问不了,就是通过填写 ip 解决的。
imherer
   4
imherer  
   2023 年 12 月 15 日
会不会是你这个函数被多次调用了?
c00WKmdje2wZLrSI
   5
c00WKmdje2wZLrSI  
OP
   2023 年 12 月 15 日
@daniel8642
@imherer

主要是这个是偶现的,而且我端口扫描脚本显示进程启动时它所需要的端口没被占用
sky96111
   6
sky96111  
   2023 年 12 月 15 日 via Android
https://zhaoji.wang/solve-the-problem-of-windows-10-ports-being-randomly-reserved-occupied-by-hyper-v/
看看是不是这个问题。我经常遇到
c00WKmdje2wZLrSI
   7
c00WKmdje2wZLrSI  
OP
   2023 年 12 月 15 日
@sky96111 不是,我是腾讯云的服务器,ubuntu22.04, 而且主要是我扫描了端口,显示未占用
zhoulq7
   8
zhoulq7  
   2023 年 12 月 15 日
如果用了 iptables 做的端口流量转发是不能通过 netstat 查到这个被占用的端口的
sky96111
   9
sky96111  
   2023 年 12 月 15 日 via Android
@c00WKmdje2wZLrSI Linux 啊,那你用 lsof -i :端口号查一下。被内核占用的端口直接是看不到的
barathrum
   10
barathrum  
   2023 年 12 月 15 日
可能是 socket 还没回收,关应用的时候如果正好有链接要等 60 秒 保证被回收,没有链接的话就能直接用了。
ss 的时候去掉 l 再看看可能发现有正在关闭状态的链接。
c00WKmdje2wZLrSI
   11
c00WKmdje2wZLrSI  
OP
   2023 年 12 月 15 日
@zhoulq7 systemctl status firewalld 和 systemctl status firewalld 显示没这两个软件
c00WKmdje2wZLrSI
   12
c00WKmdje2wZLrSI  
OP
   2023 年 12 月 15 日
@barathrum 我换了端口后,扫描新端口没被占用,但是新端口第一次启动也有几率出现说端口被占用
longbowape
   13
longbowape  
   2023 年 12 月 15 日
需要给端口设置 SO_REUSEADDR ,否则即使进程推出了也会显示一段时间的被占用。
Pythoner666666
   14
Pythoner666666  
   2023 年 12 月 15 日
云服务器有一些 厂商自带的扫描或者监控软件 他们可能是定时启动 端口也是 9999 ,所以可能刚好跟你冲突了。仅提供一个思路,不一定对哈。
barathrum
   15
barathrum  
   2023 年 12 月 15 日
你的监控脚本换一下参数,比如 netstat -neoap 啥的,端口不一定是 listen 的。
lsk569937453
   16
lsk569937453  
   2023 年 12 月 15 日
https://groups.google.com/g/golang-nuts/c/nUMvimzSZvk
不知道是不是和这个有关系,用 go build 后的二进制包启动,而不是用 go run 启动进程。
liarsa
   17
liarsa  
   2023 年 12 月 15 日
我也碰到过,但没细研究,过一会它自己就好了
c00WKmdje2wZLrSI
   18
c00WKmdje2wZLrSI  
OP
   2023 年 12 月 15 日
@lsk569937453 我使用的就是 go build 的二进制包启动的
pkoukk
   19
pkoukk  
   2023 年 12 月 15 日
简单啊,你测试下换几个端口,如果还有问题就是你代码写的问题
如果没问题就是你环境的问题
mangoDB
   20
mangoDB  
   2023 年 12 月 15 日
netstat -n | grep TIME_WAIT
julyclyde
   21
julyclyde  
   2023 年 12 月 15 日
@zhoulq7 iptables 转发的情况并不会发生冲突
只是很单纯的无法生效而已
julyclyde
   22
julyclyde  
   2023 年 12 月 15 日
if err != nil {
logger.Log.Fatal(fmt.Sprintf("err=%v", err))
请你在这里运行一下 netstat -anp
这里应该是能抓到事故现场的
}
pennai
   23
pennai  
   2023 年 12 月 16 日
你换个端口号,如果换了端口号还是同样的报错,看看是不是你写的代码有问题,这个函数跑了多次
lifei6671
   24
lifei6671  
   2023 年 12 月 17 日
你可以尝试,只启动端口,不建立客户端连接,这种情况下是不是就不存在端口被占用的情况了。
如果是的话,那么可能是因为服务器端主动断开连接后,这个服务器监听的端口需要等待 2MSL 周期才能再使用。
这个时间会很短,估计在你执行 netstat 命令的时候端口已经释放了。
可以尝试缩短 TIME_WAIT 的时间,或者在关闭服务器之前,将所有客户端都 close 了再关闭服务端。
c00WKmdje2wZLrSI
   25
c00WKmdje2wZLrSI  
OP
   2023 年 12 月 18 日
@julyclyde 感谢,抓到事故现场了,的确有进程监听了那个端口
c00WKmdje2wZLrSI
   26
c00WKmdje2wZLrSI  
OP
   2023 年 12 月 18 日
@julyclyde 说错了,是有进程使用那个端口进行非监听状态的连接,导致我使用 netstat -tuln 找不到进程,而使用 netstat -anp 找到了
julyclyde
   27
julyclyde  
   2023 年 12 月 18 日
@c00WKmdje2wZLrSI 你之前没有加-a 吧
-a 就是搜 LISTEN 的

没明白你说的“非监听状态”是啥意思啊
c00WKmdje2wZLrSI
   28
c00WKmdje2wZLrSI  
OP
   2023 年 12 月 18 日
@julyclyde chatgpt 和我说的,我也不知道那是啥意思
```
netstat -tuln | grep 9999 和 netstat -anp | grep 9999 是两个不同的命令,它们的区别在于使用的参数和显示的信息。

netstat -tuln 命令用于显示所有 TCP 和 UDP 监听的端口。它的参数含义如下:

-t:仅显示 TCP 协议相关的连接。
-u:仅显示 UDP 协议相关的连接。
-l:仅显示监听状态的连接。
-n:以数字形式显示 IP 地址和端口号。
netstat -anp 命令用于显示所有活动的 TCP 和 UDP 连接。它的参数含义如下:

-a:显示所有连接,包括监听和非监听状态的连接。
-n:以数字形式显示 IP 地址和端口号。
-p:显示与连接关联的进程信息。
根据你的描述,可能是因为在使用 netstat -tuln | grep 9999 命令时,没有找到与端口 9999 相关的监听状态的连接,所以没有显示结果。而使用 netstat -anp | grep 9999 命令时,显示了所有活动的连接,包括监听和非监听状态的连接,因此能够发现端口监听情况。
```
julyclyde
   29
julyclyde  
   2023 年 12 月 18 日
@c00WKmdje2wZLrSI GPT 说的和 manpage 也没啥区别啊

那你抓到的现场,它是 ESTABLISHED 还是 LISTEN 呢?
c00WKmdje2wZLrSI
   30
c00WKmdje2wZLrSI  
OP
   2023 年 12 月 18 日
@julyclyde ESTABLISHED
julyclyde
   31
julyclyde  
   2023 年 12 月 18 日
@c00WKmdje2wZLrSI 那我觉得 GPT 肯定不会告诉你 ip_local_port_range 这个词
c00WKmdje2wZLrSI
   32
c00WKmdje2wZLrSI  
OP
   2023 年 12 月 18 日
@julyclyde 是的,不会,而且我发现是另外一个进程和 mysql 通信时临时占用了端口,并且还是随机占用端口,一段时间后又释放了端口,不知道该怎么设置来避免
julyclyde
   33
julyclyde  
   2023 年 12 月 18 日
@c00WKmdje2wZLrSI 那你就搜搜这个词
The Go Programming Language
› http://golang.org/
› Go Playground
Go Projects
› Revel Web Framework
© 2026 V2EX · 44ms · 3.9.8.5