一尘不染

关于套接字的SO_REUSEADDR在golang中不能正常工作吗?

go

单个IP仅支持65535端口到单个目标。我希望客户端即使在会话仍处于time_wait状态的情况下,也可以在性能测试期间立即重用旧的tcp_session。

在我的Linux机器上,我已经打开了这些开关

sysctl -w net.ipv4.tcp_timestamps=1
sysctl -w net.ipv4.tcp_tw_recycle=1
sysctl -w net.ipv4.tcp_tw_reuse=1

然后,我编写以下代码来验证golang的socket_reuse选项。在代码中,我绑定了本地端口12345。

先跑后

$go run 1.go

$netstat -nat | grep 12345
tcp        0      0 192.168.1.11:12345         111.161.3.173:80            TIME_WAIT

二次运行后

$go run 1.go
Client Connect() called error: cannot assign requested address

看来SO_REUSEADDR无法工作。任何人都可以帮助解决此问题吗?

package main

import (
    "fmt"
    . "syscall"
)

func main() {
    var (
        clientsock int
        serveraddr SockaddrInet4
        err        error
    )

    if clientsock, err = Socket(AF_INET, SOCK_STREAM, IPPROTO_IP); err != nil {
        fmt.Println("Client Socket() called error:", err.Error())
        return
    }
    SetsockoptInt(clientsock, SOL_SOCKET, SO_REUSEADDR, 1)

    defer Shutdown(clientsock, SHUT_RDWR)

    serveraddr.Addr = [4]byte{111, 161, 3, 173}
    serveraddr.Port = 80

    err = Bind(clientsock, &SockaddrInet4{
        Port: 12345,
    })

    if err = Connect(clientsock, &serveraddr); err != nil {
        fmt.Println("Client Connect() called error:", err.Error())
        return
   }
}

阅读 510

收藏
2020-07-02

共1个答案

一尘不染

您应该在代码中添加两个更改:

1)设置套接字选项unix.SO_REUSEPORT。

if errReusePort := SetsockoptInt(clientsock, SOL_SOCKET, unix.SO_REUSEPORT, 1); errReusePort != nil {
    fmt.Printf("reuse port error: %v\n", errReusePort)
    return
}

2)使您的代码连接到不同的远程TCP端点。否则,由于单个源地址/端口,TCP将无法区分两个相同的连接(协议,src-addr,src-port,dst-
addr,dst-port)。下面的示例在命令行中指定两个远程服务器地址。

$ go run main.go 127.0.0.1
connected

$ go run main.go 127.0.0.2
connected

在操场上找到完整的工作代码:https//play.golang.org/p/HYLkWlVH6T4

2020-07-02