如何使用go语言为http客户端设置套接字选项(IP_TOS)?
问题描述:
我是一个新手去语言。我打算使用go语言来开发一个http客户机/服务器。 在浏览http客户端软件包中支持的功能列表时,我找不到在套餐中设置套接字选项的方法 (可能我只是不知道如何使用它)。在调用http客户端连接之前,我需要在fd中设置DSCP选项(IP_TOS)。 (尽管我发现设置套接字选项的系统调用选项,但我没有找到从http包获取fd的方法)。如何使用go语言为http客户端设置套接字选项(IP_TOS)?
在http服务器端中,能够设置套接字选项(IP_TOS)。 代码摘录:
tcpListener,err := net.ListenTCP("tcp4", addr)
if err != nil {
//fmt.Println("error in listen", err.error())
log.Fatal("net.ListenTCP()", err)
}
//get lisenet socket fd
f, _ := tcpListener.File()
err = syscall.SetsockoptInt(int(f.Fd()), syscall.SOL_SOCKET, syscall.IP_TOS, 128)
在HTTP客户端,没能得到套接字fd并设置套接字选项(IP_TOS): (我想打电话NewRequest之前设置IP_TOS)
client := &http.Client{
Transport : tr,
//Timeout: time.Duration(10) * time.Second,
}
request, err := http.NewRequest("POST", url, body)
if err != nil {
panic(err)
}
response, err := client.Do(request)
谢谢!
答
您可以为自己的自己*http.Client
http.RoundTripper
创建自己的DialContext
:
dial := func(ctx context.Context, network, addr string) (net.Conn, error) {
conn, err := (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext(ctx, network, addr)
if err != nil {
return nil, err
}
tcpConn, ok := conn.(*net.TCPConn)
if !ok {
err = errors.New("conn is not tcp")
return nil, err
}
f, err := tcpConn.File()
if err != nil {
return nil, err
}
err = syscall.SetsockoptInt(int(f.Fd()), syscall.SOL_SOCKET, syscall.IP_TOS, 128)
if err != nil {
return nil, err
}
return conn, nil
}
tr := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: dial,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
c := &http.Client{
Transport: tr,
}
resp, err := c.Get("https://google.com/")
if err != nil {
log.Fatalf("GET error: %v", err)
}
log.Printf("got %q", resp.Status)
编辑:如果您需要连接实际发生之前选项设置,你可以尝试在您的DialContext
,但这是相当不便携,不安全,不考虑上下文,并且可能会早晚破坏:
tcpAddr, err := net.ResolveTCPAddr(network, addr)
if err != nil {
return nil, err
}
sa := &syscall.SockaddrInet4{
Port: tcpAddr.Port,
Addr: [4]byte{tcpAddr.IP[0], tcpAddr.IP[1], tcpAddr.IP[2], tcpAddr.IP[3]},
}
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
if err != nil {
return nil, err
}
err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.IP_TOS, 128)
if err != nil {
return nil, err
}
err = syscall.Connect(fd, sa)
if err != nil {
return nil, err
}
file := os.NewFile(uintptr(fd), "")
conn, err := net.FileConn(file)
if err != nil {
return nil, err
}
return conn, nil
感谢您的详细回复。我已经通过示例程序测试了上面的代码,但socket客户端IP_TOS值无法在从http客户端发起的syn分组中设置。在这里,我有一个疑问,同时将参数传递给DialContext(ctx,network,addr),如何创建上下文以ctx的形式传递。目前我使用** DialContext(context.Background()网络,地址)**? –
@ManojSaha请参阅编辑并尝试。无论它是否有效,您都可能想要在Go问题跟踪器上请求一项功能,以某种方式允许FD上的设置选项。 –
再次感谢您的努力!我在示例程序中进行了测试,为api设置了dscp设置是成功的,我可以通过获取dscp的api来读取dscp值,但它并不反映在syn包中的tcp连接请求中。我仍然看到dscp是0。 –