
端口重用
发布日期:2021-05-09 03:45:46
浏览次数:10
分类:博客文章
本文共 3327 字,大约阅读时间需要 11 分钟。
目录
前言
服务器重启进程时总会提示端口已经被绑定的报错,直到重试好几次才能重启成功。
这是因为端口尚未完全关闭的情况,这时如果不设置端口重用,则无法完成绑定,因为端口还处于被别的套接口绑定的状态之中。
SO_REUSEADDR
简介
- 允许启动一个监听服务器并捆绑其众所周知端口,即使以前建立的将此端口用做他们的本地端口的连接仍存在。这通常是重启监听服务器时出现,若不设置此选项,则bind时将出错。
- 允许在同一端口上启动同一服务器的多个实例,只要每个实例捆绑一个不同的本地IP地址即可。对于TCP,我们根本不可能启动捆绑相同IP地址和相同端口号的多个服务器。
- 允许单个进程捆绑同一端口到多个套接口上,只要每个捆绑指定不同的本地IP地址即可。这一般不用于TCP服务器。
- 允许完全重复地捆绑:当一个IP地址和端口绑定到某个套接口上时,还允许此IP地址和端口捆绑到另一个套接口上。一般来说,这个特性仅在支持多播的系统上才有,而且只对UDP套接口而言(TCP不支持多播)。
Python中的用法
- 测试源码
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)
- 不允许端口重用有如下报错:
Traceback (most recent call last): File "C:\test.py", line 17, insock2.bind(tcp_listen_addr)OSError: [WinError 10048] 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。
golang用法
已经看了go源码,没能琢磨出不修改源码的方案,大家有办法搞定,记得给我说说额。
我这边是通过修改go源码,编译出来的可执行程序默认就支持端口重用。
- 修改源码:
\go\src\net\sockopt_windows.go
,按照如下方法加入一段代码。
func setDefaultSockopts(s syscall.Handle, family, sotype int, ipv6only bool) error { if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW { // Allow both IP versions even if the OS default // is otherwise. Note that some operating systems // never admit this option. syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only)) } // 加入代码,Start if family == syscall.AF_INET && sotype == syscall.SOCK_STREAM { syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) } // 加入代码,End if (sotype == syscall.SOCK_DGRAM || sotype == syscall.SOCK_RAW) && family != syscall.AF_UNIX && family != syscall.AF_INET6 { // Allow broadcast. return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)) } return nil}
- 修改源码:
\go\src\net\sockopt_linux.go
,按照如下方法加入一段代码。
func setDefaultSockopts(s, family, sotype int, ipv6only bool) error { if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW { // Allow both IP versions even if the OS default // is otherwise. Note that some operating systems // never admit this option. syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only)) } // 加入代码,Start if family == syscall.AF_INET && sotype == syscall.SOCK_STREAM { syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) } // 加入代码,End if (sotype == syscall.SOCK_DGRAM || sotype == syscall.SOCK_RAW) && family != syscall.AF_UNIX { // Allow broadcast. return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)) } return nil}
- 修改完源码,编译时需要带上
-a
强制重新编译所以包,不然还是会使用缓存的.a
文件进行编译,例如:go build -a test.go
。
其他学习
关于socket有如下5个重要元素,只要其中一个不同,那系统就能区别不同的socket连接。只要5个完全相同,则后面建立绑定的代码会报报错。
因此实际项目中,可以由不同进程对同一个端口不同IP进行绑定。例如可以同时绑定“127.0.0.0:12345”和“192.168.1.10:12345”,操作系统知道只是两个不同的绑定。
SOCKET | 本方IP | 本方Port | 目的IP | 目的Port | 协议 |
---|---|---|---|---|---|
sokcet1 | 127.0.0.1 | 8000 | 192.168.1.1 | 9000 | Tcp |
socket2 | 127.0.0.1 | 8000 | 192.168.1.1 | 10000 | Tcp |
总结
运用端口重用对于我来说最大的方便就是重启进程快了很多,不用一遍遍尝试绑定端口,都不知道啥时候可以成功。
还有就是通过学习,认识到建立监听的5个元素,只要其中一个不同,就能实例化多个socket连接。
发表评论
最新留言
很好
[***.229.124.182]2025年03月31日 04时12分52秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
netcore中使用session
2021-05-09
Android 开发学习进程0.25 自定义控件
2021-05-09
多媒体文件格式全解说(下)--图片
2021-05-09
淘宝WAP版小BUG分析
2021-05-09
【Maven】POM基本概念
2021-05-09
【Java思考】Java 中的实参与形参之间的传递到底是值传递还是引用传递呢?
2021-05-09
远程触发Jenkins的Pipeline任务的并发问题处理
2021-05-09
entity framework core在独立类库下执行迁移操作
2021-05-09
Asp.Net Core 2.1+的视图缓存(响应缓存)
2021-05-09
【wp】HWS计划2021硬件安全冬令营线上选拔赛
2021-05-09
Ef+T4模板实现代码快速生成器
2021-05-09
Java面试题:Servlet是线程安全的吗?
2021-05-09
Java集合总结系列2:Collection接口
2021-05-09
比技术还重要的事
2021-05-09
linux线程调度策略
2021-05-09
软中断和实时性
2021-05-09
Linux探测工具BCC(可观测性)
2021-05-09
Python开发之序列化与反序列化:pickle、json模块使用详解
2021-05-09
采坑 - 字符串的 "" 与 pd.isnull()
2021-05-09