我想知道,是否可以通过 websockets 协议(protocol)传输/建立 TCP 连接?
有一个websockets package似乎我可以将 TCP 连接 io.copy 到 websockets 连接中,但我不知道如何在另一端将其重新组装为 TCPConn。
例如我想创建一个socks5 一端是 ServerN(在 NAT 之后),另一端是 ServerIE。互联网用户将向 ServerIE 发出 socks5 请求(通过 socks5 协议(protocol)),ServerIE 将通过 websocket 连接将 socks5 请求发送到 ServerNAT。然后 ServerNAT 将处理 socks5 请求(即它是一个 socks5 服务器)。
编辑:
我写了一些代码,但不幸的是,它卡在了从 TCP 连接读取到 WS 的过程中。运行它:go run main.go -logtostderr
package main
import (
"flag"
log "github.com/golang/glog"
"golang.org/x/net/websocket"
"bufio"
"net"
"net/http"
"time"
// "io"
)
func main() {
flag.Parse()
defer log.Flush()
log.Infof("wsServer()")
wsCh := wsServer()
log.Infof("wsNAT()")
natWS, err := wsNAT()
if err != nil {
log.Error(err)
return
}
done := make(chan struct{}, 1)
log.Infof("listenTCP()")
conn := listenTCP()
buf := bufio.NewReader(conn)
go func() {
log.Infof("Write TCP to WS")
n, err := buf.WriteTo(natWS)
if err != nil {
log.Fatal(err)
return
}
log.Infof("newConn.ws.ReadFrom(conn) %v", n)
close(done)
}()
wsToTCP(<- wsCh)
<-done
}
// wsNAT dials /ws endpoint and returns a websocket connection.
func wsNAT() (*websocket.Conn, error) {
time.Sleep(1 * time.Second)
origin := "http://localhost/"
url := "ws://localhost:12345/ws"
return websocket.Dial(url, "", origin)
}
// wsServer returns the websocket
// connections received on /ws endpoint
func wsServer() chan *websocket.Conn {
wsCh := make(chan *websocket.Conn, 1)
http.Handle("/ws", websocket.Handler(func(ws *websocket.Conn) {
wsCh <- ws
time.Sleep(1 *time.Hour)
}))
go func() {
err := http.ListenAndServe(":12345", nil)
if err != nil {
panic("ListenAndServe: " + err.Error())
}
}()
return wsCh
}
// wsToTCP reads a ws connection and converts its payload
// to a TCP connection.
func wsToTCP(ws *websocket.Conn) {
conn := &net.TCPConn{}
var msg []byte
if _, err := ws.Read(msg); err != nil {
log.Error(err)
return
}
log.Infof("msg %v", msg)
n, err := conn.Write(msg)
if err != nil {
log.Errorf("conn.Write %v, msg %v", err, msg)
return
}
log.Infof("conn is %v, copied %v", conn, n)
// END: do something with the connection
// .....
}
//ListenTCP returns the first TCP connection received on port 8080
func listenTCP() *net.TCPConn {
addr := &net.TCPAddr{IP: net.ParseIP("0.0.0.0"), Port: 8080}
lr, err := net.ListenTCP("tcp", addr)
if err != nil {
panic(err)
}
defer lr.Close()
ieConn, err := lr.AcceptTCP()
if err != nil {
panic(err)
}
log.Infof("connection accepted")
return ieConn
}
要触发 TCP 监听器,您可以在端口 8080 上发出请求(例如 curl --socks5 localhost:8080 google.com -v
或 curl localhost:8080 -v
)
最佳答案
这应该没有问题。我已经在许多协议(protocol)上构建了 TCP 转发器。从来没有 WebSockets,但我看不出有什么不同的原因。
你有两个问题:
- 建立连接的正确方法是使用
net.Dial
,而不是仅仅创建一个net.TCPConn
。 - 你只是在一个方向上复制。您需要双向复制。
这是我今天早上为不同目的构建的一个 super 简单的代理(我的完整代码经常破坏数据包,所以我可以测试坏的连接)。它应该可以转换为许多其他用途:
func run(inPort int, dest string) {
l, err := net.Listen("tcp", fmt.Sprintf(":%d", inPort))
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
fmt.Printf("http://%v -> %s\n", l.Addr(), dest)
for {
conn, err := l.Accept()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Connection from %s\n", conn.RemoteAddr())
go proxy(conn, dest)
}
}
func proxy(in net.Conn, dest string) {
out, err := net.Dial("tcp", dest)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
go io.Copy(out, in)
io.Copy(in, out)
fmt.Printf("Disconnect from %s\n", in.RemoteAddr())
}
您只需将此处的 net.Dial
替换为对服务器的 WS 调用,并在服务器端使用 net.Dial
将其转发。
但最关键的一点可能是最后几行。你必须双向复制,而人们忘记了这一点。
关于tcp - 是否可以通过 websockets 或其他协议(protocol)传输 TCP 连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32135763/