Golang的gorilla/websocket包使用时,Websocket连接会断开

4
我试图使用gorilla/websocket包将一个建立并维护与第三方服务器的Websocket连接的NodeJS脚本移植到Go中。在Node脚本中,收到ping后会收到pong,并且连接会无限期保持活动状态。在Go脚本中,ping/pong有效,但是服务器在约30秒后断开连接。
我怀疑使用Go websocket包发送的pings格式不正确,但我无法确定原因。比较运行这些程序时捕获的加密网络流量显示TCP请求和响应的响应长度没有差异,因此可能不是问题所在。非常感谢任何帮助!

websocket.js

#!/usr/bin/env node

// npm install websocket@1.0.25 --save
const WebSocketClient = require('websocket').client;
const client = new WebSocketClient();

let lastPing = new Date().getTime();

client.on('connectFailed', function(error) {
    console.log('Connect Error: ' + error.toString());
});

client.on('connect', function(connection) {
    console.log('Connected to Server...');
    connection.on('error', function(error) {
        console.log("Connection Error: " + error.toString());
    });
    connection.on('close', function() {
        console.log('Connection Closed');
    });
    connection.on('message', function(message) {
      if (message.type === 'utf8') {
        console.log(message.utf8Data);
      }
    });
    connection.on('pong', function(){
      console.log('[pingpong] response took', (new Date().getTime() - lastPing) + 'ms');
    })

    function send(message) {
      if (connection.connected) {
          connection.sendUTF(message);
      }
    }

    // Send a ping every 10s
    // to keep the connection live
    setInterval(function(){
      lastPing = new Date().getTime();
      connection.ping();
    }, 10000);
});

client.connect('wss://ws.radarrelay.com/0x/v0/ws');

websocket.go

package main

import (
    "flag"
    "log"
    "os"
    "os/signal"
    "time"

    "github.com/gorilla/websocket"
)

var addr = "wss://api.radarrelay.com/0x/v0/ws"

func main() {
    flag.Parse()
    log.SetFlags(0)

    timeoutDuration := 2 * time.Minute

    interrupt := make(chan os.Signal, 1)
    signal.Notify(interrupt, os.Interrupt)

    c, _, err := websocket.DefaultDialer.Dial(addr, nil)
    if err != nil {
        log.Fatal("dial:", err)
    } else {
        log.Println("Connected to server")
    }

    c.SetPongHandler(func(str string) error {
        log.Println("pong received", str)
        return nil
    })

    defer c.Close()

    done := make(chan struct{})

    go func() {
        defer c.Close()
        defer close(done)
        for {
            c.SetReadDeadline(time.Now().Add(timeoutDuration))
            _, message, err := c.ReadMessage()
            if err != nil {
                log.Println("read:", err)
                return
            }
            if len(message) >= 2 {
                message = message[2:]
            }
            log.Printf("recv: %s", message)
        }
    }()

    ticker := time.NewTicker(10 * time.Second)
    defer ticker.Stop()

    for {
        select {
        case _ = <-ticker.C:
            err := c.WriteMessage(websocket.PingMessage, []byte{})
            if err != nil {
                log.Println("write:", err)
                return
            } else {
                log.Println("ping sent")
            }
        case <-interrupt:
            log.Println("interrupt")
            // To cleanly close a connection, a client should send a close
            // frame and wait for the server to close the connection.
            err := c.WriteMessage(
                websocket.CloseMessage,
                websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
            if err != nil {
                log.Println("write close:", err)
                return
            }
            select {
            case <-done:
            case <-time.After(time.Second):
            }
            c.Close()
            return
        }
    }
}

1
让我们来看一些代码。 - Peter
1
@MaxGillett:在您的帖子中始终包含一个 [mcve] 的代码(请参见 [ask])。 - JimB
请将代码粘贴在这里。网站规定问题中必须包含代码,而不仅仅是链接。 - Peter
@CeriseLimón 是的,但从这个特定的第三方服务器的角度来看是格式错误的。上面的Golang脚本可以为我投掷的任何其他websocket服务器保持连接,包括我自己启动的服务器。我想比较每个脚本发送的ping帧的未加密内容,但我不知道如何去做。 - Max Gillett
要记录未加密的数据,请在Go代码中添加fmt.Println("frame: %x %x\n", buf0, buf1)(https://github.com/gorilla/websocket/blob/eb925808374e5ca90c83401a40d711dc08c0c0f6/conn.go#L376),并在JS代码中添加`console.log(output);`(https://github.com/theturtle32/WebSocket-Node/blob/d941f975e8ef6b55eafc0ef45996f4198013832c/lib/WebSocketFrame.js#L270)。 - Charlie Tumahai
显示剩余6条评论
1个回答

4
两者之间的地址不同。节点代码正在通信。
wss://ws.radarrelay.com/0x/v0/ws

这段go代码正在与以下内容通信:

wss://api.radarrelay.com/0x/v0/ws

看起来这些解析成不同的IP地址,因此它们可能有不同的入口基础设施,并且在api子域上存在一个超时,而在ws子域上不存在。


1
如果这被证明是真正的问题,那么很好地捕捉到了它 :-) - Tarun Lalwani

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接