经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Go语言 » 查看文章
端口重用
来源:cnblogs  作者:janbar  时间:2020/11/16 10:27:48  对本文有异议

前言

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

SO_REUSEADDR

简介

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

Python中的用法

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

golang用法

已经看了go源码,没能琢磨出不修改源码的方案,大家有办法搞定,记得给我说说额。
我这边是通过修改go源码,编译出来的可执行程序默认就支持端口重用。

  1. 修改源码:\go\src\net\sockopt_windows.go,按照如下方法加入一段代码。
  1. func setDefaultSockopts(s syscall.Handle, family, sotype int, ipv6only bool) error {
  2. if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
  3. // Allow both IP versions even if the OS default
  4. // is otherwise. Note that some operating systems
  5. // never admit this option.
  6. syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
  7. }
  8. // 加入代码,Start
  9. if family == syscall.AF_INET && sotype == syscall.SOCK_STREAM {
  10. syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
  11. }
  12. // 加入代码,End
  13. if (sotype == syscall.SOCK_DGRAM || sotype == syscall.SOCK_RAW) && family != syscall.AF_UNIX && family != syscall.AF_INET6 {
  14. // Allow broadcast.
  15. return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
  16. }
  17. return nil
  18. }
  1. 修改源码:\go\src\net\sockopt_linux.go,按照如下方法加入一段代码。
  1. func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
  2. if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
  3. // Allow both IP versions even if the OS default
  4. // is otherwise. Note that some operating systems
  5. // never admit this option.
  6. syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
  7. }
  8. // 加入代码,Start
  9. if family == syscall.AF_INET && sotype == syscall.SOCK_STREAM {
  10. syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
  11. }
  12. // 加入代码,End
  13. if (sotype == syscall.SOCK_DGRAM || sotype == syscall.SOCK_RAW) && family != syscall.AF_UNIX {
  14. // Allow broadcast.
  15. return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
  16. }
  17. return nil
  18. }
  1. 修改完源码,编译时需要带上-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连接。

原文链接:http://www.cnblogs.com/janbar/p/13965098.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号