golang端口重用
创始人
2025-06-01 14:36:43

文章目录

    • 前言
    • SO_REUSEADDR
      • 简介
      • Python中的用法
      • golang用法
    • 其他学习
    • 总结

前言

服务器重启进程时总会提示端口已经被绑定的报错,直到重试好几次才能重启成功。
这是因为端口尚未完全关闭的情况,这时如果不设置端口重用,则无法完成绑定,因为端口还处于被别的套接口绑定的状态之中。

SO_REUSEADDR

简介

  1. 允许启动一个监听服务器并捆绑其众所周知端口,即使以前建立的将此端口用做他们的本地端口的连接仍存在。这通常是重启监听服务器时出现,若不设置此选项,则bind时将出错。
  2. 允许在同一端口上启动同一服务器的多个实例,只要每个实例捆绑一个不同的本地IP地址即可。对于TCP,我们根本不可能启动捆绑相同IP地址和相同端口号的多个服务器。
  3. 允许单个进程捆绑同一端口到多个套接口上,只要每个捆绑指定不同的本地IP地址即可。这一般不用于TCP服务器。
  4. 允许完全重复地捆绑:当一个IP地址和端口绑定到某个套接口上时,还允许此IP地址和端口捆绑到另一个套接口上。一般来说,这个特性仅在支持多播的系统上才有,而且只对UDP套接口而言(TCP不支持多播)。

Python中的用法

  1. 测试源码
import socketserveripaddr = '127.0.0.1'
tcp_listen_addr = (serveripaddr, 12345)
set_reuse_addr = False # True:允许重用,不会报错.False:默认不支持重用,会报错sock1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if set_reuse_addr:sock1.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock1.bind(tcp_listen_addr)
sock1.listen(1)sock2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if set_reuse_addr:sock2.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock2.bind(tcp_listen_addr)
sock2.listen(1)
  1. 不允许端口重用有如下报错:
Traceback (most recent call last):File "C:\test.py", line 17, in sock2.bind(tcp_listen_addr)
OSError: [WinError 10048] 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。

golang用法

  1. window方法
package mainimport ("context""log""net""syscall"
)func main() {l := &net.ListenConfig{Control: reusePortControl}s, err := l.Listen(context.Background(), "tcp", ":8080")if err != nil {log.Fatal(err)}defer s.Close()for {c, err := s.Accept()if err != nil {log.Fatal(err)}go func(c net.Conn) {// 业务逻辑}(c)}
}func reusePortControl(network, address string, c syscall.RawConn) error {var opErr errorerr := c.Control(func(fd uintptr) {opErr = syscall.SetsockoptInt(syscall.Handle(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)})if err != nil {return err}return opErr
}
  1. Linux方法
package mainimport ("context""log""net""syscall"
)func main() {l := &net.ListenConfig{Control: reusePortControl}s, err := l.Listen(context.Background(), "tcp", ":8080")if err != nil {log.Fatal(err)}defer s.Close()for {c, err := s.Accept()if err != nil {log.Fatal(err)}go func(c net.Conn) {// 业务逻辑}(c)}
}func reusePortControl(network, address string, c syscall.RawConn) error {var opErr errorerr := c.Control(func(fd uintptr) {// syscall.SO_REUSEPORT ,在Linux下还可以指定端口重用opErr = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)})if err != nil {return err}return opErr
}

其他学习

关于socket有如下5个重要元素,只要其中一个不同,那系统就能区别不同的socket连接。只要5个完全相同,则后面建立绑定的代码会报报错。
因此实际项目中,可以由不同进程对同一个端口不同IP进行绑定。例如可以同时绑定“127.0.0.0:12345”和“192.168.1.10:12345”,操作系统知道只是两个不同的绑定。

SOCKET本方IP本方Port目的IP目的Port协议
sokcet1127.0.0.18000192.168.1.19000Tcp
socket2127.0.0.18000192.168.1.110000Tcp

总结

运用端口重用对于我来说最大的方便就是重启进程快了很多,不用一遍遍尝试绑定端口,都不知道啥时候可以成功。
还有就是通过学习,认识到建立监听的5个元素,只要其中一个不同,就能实例化多个socket连接。

相关内容

热门资讯

玛雅人的五大预言 玛雅人预言2... 曾经玛雅人预言2012年是世界末日,但当时好像没有发生什么。没想到10年后的2022年,疫情,战争,...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
cad打印线条粗细设置 cad... 004-线型(下)打印样式设置和线型文件使用一、线宽设置方法制图规范里边的线宽要求,我们已经定义好,...
阿西吧是什么意思 阿西吧相当于... 即使你没有受到过任何外语培训,你也懂四国语言。汉语:你好英语:Shit韩语:阿西吧(아,씨발! )日...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...