【问题标题】:Pinging Websocket server with Websocket .NET client使用 Websocket .NET 客户端 ping Websocket 服务器
【发布时间】:2020-10-16 13:52:12
【问题描述】:

我试图弄清楚如何发送ping/pong 心跳,以确保在 .NET Core WPF 应用程序中使用Websocket .NET client 与 Websocket 服务器保持连接,所以我用this Binance Websocket 进行测试,上面写着

websocket 服务器将每 3 分钟发送一次ping frame。如果 websocket 服务器在 10 分钟内没有收到来自连接的pong frame,则连接将被断开。允许未经请求的pong frames

但是,当我尝试使用我的示例代码进行连接时,我根本不会从 websocket 收到任何包含字符串 ping 的消息,并且如果至少订阅了一个流,连接似乎永远不会失败。同样发送未经请求的pong 消息似乎总是抛出error 3: invalid JSON,然后断开连接。

ping/pong 心跳是由 NuGet 包管理的(尽管我没有在其源代码中找到任何提到 pingpong 的行),或者根本不支持它们?如果是这样,那么我与 Binance Websocket 的连接如何/为什么没有断开?

这是我的 WSClient 类的示例代码,因此您可以尝试看看即使在 +15 分钟后您也不会断开连接:

更新:它由WebsocketClient 内部处理,KeepAliveInterval 实际上是在每个间隔发送pong 帧。我想知道是否可以订阅一些事件以查看这些帧何时发送,这在处理严格的消息速率限制时可能很有用,以便在与 pong 帧同时发送最大数量的消息时不会意外断开连接正在发送。

using System;
using System.Net.WebSockets;
using Websocket.Client;
using Websocket.Client.Models;
using System.Threading.Tasks;
using System.Reactive.Linq;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;

public class WSClient
{
    private List<string> logs = new List<string>();

    private WebsocketClient client;
    private string wsUrl = "wss://stream.binance.com/ws";
    
    public WSClient() { }

    public async Task InitializeClient()
    {
        Uri uri = new Uri(wsUrl);
        Func<ClientWebSocket> factory = new Func<ClientWebSocket>(() => {
            ClientWebSocket wsClient = new ClientWebSocket
            {
                Options =
                {
                    KeepAliveInterval = TimeSpan.FromSeconds(5) // interval to send pong frames             }
            };

            return wsClient;
        });

        client = new WebsocketClient(uri, factory);
        client.Name = "WebsocketClient";
        client.ReconnectTimeout = TimeSpan.FromSeconds(30);
        client.ErrorReconnectTimeout = TimeSpan.FromSeconds(30);

        client.ReconnectionHappened.Subscribe(OnReconnection);
        client.DisconnectionHappened.Subscribe(OnDisconnect);

        client.MessageReceived
            .Where((ResponseMessage message) => message.MessageType == WebSocketMessageType.Text)
            .Subscribe(OnMessage);

        try
        {
            await client.StartOrFail();
        }
        catch (Exception ex)
        {
            logs.Add($"Error: { ex.Message }");
        }

        // Subscribing to a stream (btcusdt@aggTrade for example)
        client.Send("{\"method\": \"SUBSCRIBE\",\"params\":[\"btcusdt@aggTrade\"],\"id\": 1}");
    }

    private void OnReconnection(ReconnectionInfo info)
    {
        logs.Add("Reconnected");
    }

    private void OnMessage(ResponseMessage message)
    {
        logs.Add(message.Text);
    }

    private void OnDisconnect(DisconnectionInfo info)
    {
        logs.Add("Diconnected");
    }
}

【问题讨论】:

  • 使用像wireshark或fiddler这样的嗅探器来帮助调试。检查响应正文以查看字符串的实际外观。 Http 使用 TCP 作为传输层。正常 TCP Keep-Alive 发送一个没有 Keep-Alive 数据的数据包。尚未查看 Github 代码以了解实际使用的内容。
  • @jdweng 我尝试使用wireshark,但奇怪的是,接收到的消息不是使用Websocket协议捕获的,而是TLSv1.2。除此之外,我无法阅读任何意义信息。
  • HTTP 协议 (websocket) 在 TLS 验证之前不会发生。因此,您可能会看到 TLS 身份验证发生,但失败了。所以服务器可能需要 TLS 1.3 而不是 1.2。或者证书可能没有加载或使用了错误的加密模式。您的客户端中似乎没有任何 TLS 选项。所以它必须默认为操作系统(或内核)。那么你使用的是什么版本的核心。您的机器使用什么内核?
  • @jdweng 我目前在 Windows 10 (版本 1903) 上使用 .NET Core 3.1。最有趣的部分是我仍然可以使用那个 c# 客户端接收功能数据。我还尝试了另外两个类似的 Websocket 服务器BitmexBitfinex,它们也都出现在仅发送TLSv1.2 数据包的wireshark 中。但是,这些服务器不需要发送第一个所需的 ping/pong 原始帧。

标签: c# .net-core websocket


【解决方案1】:

我认为WebSocketClient 在幕后处理乒乓协议。我相信你不必担心。

【讨论】:

  • 你是对的,在进一步研究源代码后,它会自动用 pong 响应每个 ping 帧。此外,ClientWebSocketKeepAliveInterval 选项实际上是在每个间隔发送一个 pong 帧,而不仅仅是基本的 TCP KeepAlive。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-26
相关资源
最近更新 更多