使用Go语言创建多进程共享端口监听

发表时间: 2024-05-20 17:41

HTTP 多进程监听一个端口

常见的问题: listen tcp :8000: bind: address already in use

方式一

package mainimport (    "context"    "fmt"    "net"    "net/http"    "os"    "syscall"    "golang.org/x/sys/unix" // unix 包 不支持 window 操作系统)var lc = net.ListenConfig{Control: func(network, address string, c syscall.RawConn) error {var opErr errorif err := c.Control(func(fd uintptr) {		opErr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)    }); err != nil {        return err    }    return opErr    },}func main() {    pid := os.Getpid()    // 绑定监听端口    l, err := lc.Listen(context.Background(), "tcp", "127.0.0.1:8000")    if err != nil {        panic(err)    }    server := &http.Server{}    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {        w.WriteHeader(http.StatusOK)        fmt.Fprintf(w, "客户端 Client [%s] Received msg from Server PID: [%d] \n", r.RemoteAddr, pid)    })    fmt.Printf("服务端 Server with PID: [%d] is running \n", pid)    _ = server.Serve(l)}
> # go run http.goServer with PID: [56730] is running> # go run http.goServer with PID: [57172] is running

方式二:

package mainimport (    "context"    "fmt"    "net"    "net/http"    "os"    "syscall"    "github.com/sirupsen/logrus"    "golang.org/x/sys/unix")type TestHandler struct {    RESP []byte}func (handler *TestHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {    resp.WriteHeader(200)    resp.Write(handler.RESP)}func Control(network, address string, c syscall.RawConn) error {    var err error    c.Control(func(fd uintptr) {        err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)        if err != nil {            logrus.Error("Failed to set sock SO_REUSEADDR. ", err)            return        }        err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)        if err != nil {            logrus.Error("Failed to set sock SO_REUSEPORT. ", err)            return        }    })    return err}func main() {    // 获取进程id号    pid := os.Getpid()    lc := &net.ListenConfig{        Control: Control,    }    // 第二个参数必须是"tcp"、"tcp4"、"tcp6", 一般使用tcp, 兼容tcp4 和 tcp6    ln, err := lc.Listen(context.Background(), "tcp", "127.0.0.1:8000")    if err != nil {        logrus.Panic("Failed to listen. ", err)    }    fmt.Printf("Server with PID: [%d] is running \n", pid)    err = http.Serve(ln, &TestHandler{        RESP: []byte("127.0.0.1:8000"),    })    if err != nil {        logrus.Panic("Failed to listen. ", err)    }}
> # go run http.goServer with PID: [76512] is running> # go run http.goServer with PID: [76632] is running

注意: 以上代码只能运行在 Linux 平台下;

window 平台下支持 一个端口 创建 libp2p服务和一个HTTP服务 监听一个端口号;