求助,Golang Go语言中端口占用的问题

发布于 1周前 作者 sinazl 来自 Go语言

环境: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 进程时,端口占用问题又消失了 这到底是怎么一回事,而且这情况不是必现的,是偶尔会出现


求助,Golang Go语言中端口占用的问题

更多关于求助,Golang Go语言中端口占用的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

34 回复

各位大哥有没有解决的思路可以说一说

更多关于求助,Golang Go语言中端口占用的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


写个其它语言的代码看看能不能监听这个端口

0.0.0.0:9999
可以试试填写一下需要绑定到的网卡 ip 地址。
之前在 wsl2 上出现绑定之后访问不了,就是通过填写 ip 解决的。

会不会是你这个函数被多次调用了?




主要是这个是偶现的,而且我端口扫描脚本显示进程启动时它所需要的端口没被占用

不是,我是腾讯云的服务器,ubuntu22.04, 而且主要是我扫描了端口,显示未占用

如果用了 iptables 做的端口流量转发是不能通过 netstat 查到这个被占用的端口的

Linux 啊,那你用 lsof -i :端口号查一下。被内核占用的端口直接是看不到的

可能是 socket 还没回收,关应用的时候如果正好有链接要等 60 秒 保证被回收,没有链接的话就能直接用了。
ss 的时候去掉 l 再看看可能发现有正在关闭状态的链接。

systemctl status firewalld 和 systemctl status firewalld 显示没这两个软件

我换了端口后,扫描新端口没被占用,但是新端口第一次启动也有几率出现说端口被占用

需要给端口设置 SO_REUSEADDR ,否则即使进程推出了也会显示一段时间的被占用。

云服务器有一些 厂商自带的扫描或者监控软件 他们可能是定时启动 端口也是 9999 ,所以可能刚好跟你冲突了。仅提供一个思路,不一定对哈。

你的监控脚本换一下参数,比如 netstat -neoap 啥的,端口不一定是 listen 的。

https://groups.google.com/g/golang-nuts/c/nUMvimzSZvk
不知道是不是和这个有关系,用 go build 后的二进制包启动,而不是用 go run 启动进程。

我也碰到过,但没细研究,过一会它自己就好了

我使用的就是 go build 的二进制包启动的

简单啊,你测试下换几个端口,如果还有问题就是你代码写的问题
如果没问题就是你环境的问题

netstat -n | grep TIME_WAIT

iptables 转发的情况并不会发生冲突
只是很单纯的无法生效而已

if err != nil {
logger.Log.Fatal(fmt.Sprintf(“err=%v”, err))
请你在这里运行一下 netstat -anp
这里应该是能抓到事故现场的
}

你换个端口号,如果换了端口号还是同样的报错,看看是不是你写的代码有问题,这个函数跑了多次

你可以尝试,只启动端口,不建立客户端连接,这种情况下是不是就不存在端口被占用的情况了。
如果是的话,那么可能是因为服务器端主动断开连接后,这个服务器监听的端口需要等待 2MSL 周期才能再使用。
这个时间会很短,估计在你执行 netstat 命令的时候端口已经释放了。
可以尝试缩短 TIME_WAIT 的时间,或者在关闭服务器之前,将所有客户端都 close 了再关闭服务端。

感谢,抓到事故现场了,的确有进程监听了那个端口

说错了,是有进程使用那个端口进行非监听状态的连接,导致我使用 netstat -tuln 找不到进程,而使用 netstat -anp 找到了

你之前没有加-a 吧
-a 就是搜 LISTEN 的

没明白你说的“非监听状态”是啥意思啊

chatgpt 和我说的,我也不知道那是啥意思
<br>netstat -tuln | grep 9999 和 netstat -anp | grep 9999 是两个不同的命令,它们的区别在于使用的参数和显示的信息。<br><br>netstat -tuln 命令用于显示所有 TCP 和 UDP 监听的端口。它的参数含义如下:<br><br>-t:仅显示 TCP 协议相关的连接。<br>-u:仅显示 UDP 协议相关的连接。<br>-l:仅显示监听状态的连接。<br>-n:以数字形式显示 IP 地址和端口号。<br>netstat -anp 命令用于显示所有活动的 TCP 和 UDP 连接。它的参数含义如下:<br><br>-a:显示所有连接,包括监听和非监听状态的连接。<br>-n:以数字形式显示 IP 地址和端口号。<br>-p:显示与连接关联的进程信息。<br>根据你的描述,可能是因为在使用 netstat -tuln | grep 9999 命令时,没有找到与端口 9999 相关的监听状态的连接,所以没有显示结果。而使用 netstat -anp | grep 9999 命令时,显示了所有活动的连接,包括监听和非监听状态的连接,因此能够发现端口监听情况。<br>

GPT 说的和 manpage 也没啥区别啊

那你抓到的现场,它是 ESTABLISHED 还是 LISTEN 呢?

那我觉得 GPT 肯定不会告诉你 ip_local_port_range 这个词

是的,不会,而且我发现是另外一个进程和 mysql 通信时临时占用了端口,并且还是随机占用端口,一段时间后又释放了端口,不知道该怎么设置来避免

那你就搜搜这个词

在Golang中遇到端口占用问题通常是由于你的应用程序试图绑定一个已经被其他进程占用的端口。以下是一些解决步骤和建议:

  1. 检查端口占用

    • 使用命令行工具检查端口占用情况。例如,在Linux或macOS上,你可以使用lsof -i :<port>netstat -tulpn | grep :<port>命令。在Windows上,可以使用netstat -aon | findstr :<port>
  2. 关闭占用端口的进程

    • 一旦找到占用端口的进程ID(PID),你可以决定是否关闭该进程。在Linux或macOS上,可以使用kill -9 <PID>命令。在Windows上,可以在任务管理器中找到并结束该进程,或者使用taskkill /PID <PID> /F命令。
  3. 修改应用程序的端口

    • 如果关闭占用端口的进程不是一个选项,你可以考虑修改你的Golang应用程序使用的端口。
  4. 使用代码检查端口占用

    • 在你的Golang代码中,你可以尝试绑定端口,并在捕获到错误时检查是否是端口占用错误(通常是listen tcp :<port>: bind: address already in use)。如果是,你可以采取适当的行动,比如打印错误信息、重试使用其他端口或退出程序。
  5. 使用SO_REUSEADDR套接字选项

    • 在绑定端口之前,可以设置套接字选项SO_REUSEADDR,这允许在同一端口上启动服务器的多个实例(尽管这通常用于UDP或需要快速重启TCP服务器的场景)。

希望这些步骤能帮助你解决Golang中的端口占用问题。

回到顶部