gpt4 book ai didi

http - 有没有办法使用特定的 TCPConn 来发出 HTTP 请求?

转载 作者:可可西里 更新时间:2023-11-01 16:58:54 28 4
gpt4 key购买 nike

我正在尝试建立一种在运行 Go 的中央服务器和一组物联网设备(也运行 Go)之间进行通信的方法。

对于每个设备,它通过持久的 TCPConn 连接到中央服务器。这些设备位于路由器后面。中央服务器保存该连接并通过它发送/接收消息。现在,它功能齐全并且可以正常工作。

但是,现在消息传递变得非常复杂,因此必须使用 HTTP 而不是纯 TCP 提供的实用程序。

我试图编写一个返回上述连接的 http.Transport 版本。但是,我无法从 Dial/DialContext 函数提供和返回有效连接。

物联网设备

func main() {

http.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})

tcpAddr, err := net.ResolveTCPAddr("tcp", "###.###.###.###:8533")
if err != nil {
panic(err)
}

conn, err := net.DialTCP("tcp", nil, tcpAddr)
if err != nil {
panic(err)
}

err = conn.SetKeepAlive(true)
if err != nil {
panic(err)
}

err = conn.SetKeepAlivePeriod(time.Second * 10)
if err != nil {
panic(err)
}

fmt.Println("Listening")
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
}

中央服务器

func main() {
tcpAddr, err := net.ResolveTCPAddr("tcp", port)
if err != nil {
panic(err)
}
listener, err := net.ListenTCP("tcp", tcpAddr)

if err != nil {
panic(err)
}

conn, err := listener.AcceptTCP()
if err != nil {
panic(err)
}
fmt.Println("Received conn, attempting to send HTTP through connection")

dialFunc := func(network, addr string) (net.Conn, error) {
return conn, nil
}

t := http.Transport{
Dial: dialFunc,
}

client := http.Client{
Transport: &t,
}

fmt.Println("Making request")
res, err := client.Get("http://www.shouldNotMatter.com:8080/foo") // HANGS HERE
if err != nil {
fmt.Println(err)
}

fmt.Println("Received response")
defer res.Body.Close()

if res.StatusCode == http.StatusOK {
bodyBytes, err := ioutil.ReadAll(res.Body)
if err != nil {
panic(err)
}
bodyString := string(bodyBytes)
fmt.Println(bodyString)
} else {
fmt.Println(res)
}
}

使用调试器查看它挂起的位置后,它似乎在 pconn 往返期间卡在了 select 语句中。 https://golang.org/src/net/http/transport.go?s=3397:10477 中的第 2420 行

最佳答案

创建一个从拨号方法返回现有连接的类型:

type connDialer struct {
c net.Conn
}

func (cd connDialer) Dial(network, addr string) (net.Conn, error) {
return cd.c, nil
}

使用拨号method value在交通工具中:

client := http.Client{Transport: &http.Transport{Dial: connDialer{c}.Dial}}

其中 c 是现有的 net.Conn

试试the playground (它适用于一次请求。当客户端调用第二个连接时它将失败)。

总体方法是脆弱的。考虑使用旨在支持双向通信的 WebSocket、gRPC 或其他协议(protocol)。

关于http - 有没有办法使用特定的 TCPConn 来发出 HTTP 请求?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58228560/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com