多個程序監聽同一端口 - socket端口復用技術


https://www.jianshu.com/p/ce277812eca2

 

 

對於多個程序綁定同一個端口我們遇到最多的是(Port 80 was already in use),也就是說端口被占用,不能重復綁定,但是操作系統內核支持通過配置socket參數的方式來實現多個進程綁定同一個端口。

簡單示例

package main

import (
    "context"
    "golang.org/x/sys/windows"
    "net"
    "syscall"
)

var listenConfig = net.ListenConfig{
    Control:   MyControl,
}

func MyControl(network, address string, c syscall.RawConn) error {
    return c.Control(func(fd uintptr) {
        err := windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_REUSEADDR, 1)
        if err != nil {
            panic(err)
        }
    })
}

func main() {
    listener, err := listenConfig.Listen(context.Background(), "tcp", "127.0.0.1:8080")

    if err != nil {
        panic(err)
    }
    defer listener.Close()
    for {
        conn, err := listener.Accept()
        if err == nil {
            println("new connection ", conn.RemoteAddr().String())
        }
    }
}

執行該程序后發現多個進程可以綁定同一端口

port_reuse.png

進程12720,3632和13612同時綁定了8080端口

原理解析

這個例子關鍵代碼是設置socket的SO_REUSEADDR參數
實現多個程序綁定一個端口windows下需要設置SO_REUSEADDR參數
linux下需要設置SO_REUSEADDR和SO_REUSEPORT參數

對於windows和linux系統SO_REUSEADDR參數含義並不相同
Windows系統:
using-so-reuseaddr-and-so-exclusiveaddruse
so-exclusiveaddruse

Linux系統:
The SO_REUSEPORT socket option

socket man

相關問題:
how-do-so-reuseaddr-and-so-reuseport-differ
可以看出Windows下SO_REUSEADDR可以用來端口復用,在Linux下SO_REUSEADDR為了實現TIME_WAIT階段的快速綁定,SO_REUSEPORT用來配置端口復用

安全問題

由此引發了一個安全問題,如果一個正常的web程序監聽80端口提供服務,其它惡意程序同樣監聽了80端口,那么發送到80端口的請求就會被惡意程序接收並處理,這是我們不願看到的。

Linux下處理方式為所有端口復用的進程必須在同一個用戶下
Windows下處理方式為添加SO_EXECLUSIVEADDRUSE參數,程序設置該參數后,其它程序就不能復用這個端口

SO_REUSEADDR: Allows a socket to bind to an address and port already in use. The SO_EXCLUSIVEADDRUSE option can prevent this.

開箱即用

c語言程序直接調用setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuse_port, sizeof(reuse_port));函數即可

golang包greuse提供了開箱即用的端口復用功能,兼容多系統 https://github.com/gogf/greuse

其它語言程序可以通過調用bindp項目實現https://github.com/yongboy/bindp

作者:寫個代碼容易么
鏈接:https://www.jianshu.com/p/ce277812eca2
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM