I am trying to stream bitcoin prices from the Huobi USDT Swaps but my ping/pong mechanism is not working so Huobi is always closing the connection after 30 seconds.
This is what the documentation says https://huobiapi.github.io/docs/usdt_swap/v1/en/#market-heartbeat:
WebSocket API supports two-way heartbeat. Both Server and Client can send ping message, which the opposite side can return with pong message.
WebSocket Server sends heartbeat: {"ping": 18212558000}
WebSocket Client should respond:: {"pong": 18212558000}
Note: Once the WebSocket Client and WebSocket Server get connected, the server will send a heartbeat every 5 seconds (the frequency might change). The connection will get disconnected automatically if the WebSocket Client ignores the heartbeat message for 5 times. The server will remain connection if the WebSocket Client responds one “ping” value within the latest 2 heartbeat messages.
using System;
using System.IO;
using System.IO.Compression;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
namespace HuobiMarketWebSocketTest
{
class HuobiMarketWebSocketTest
{
public static void Main(string[] args)
{
int pings = 0;
ClientWebSocket ClientWebSocket = new ClientWebSocket();
string symbol = "btcusdt";
ClientWebSocket.ConnectAsync(new Uri("wss://api.hbdm.com/linear-swap-ws"), CancellationToken.None).Wait();
try
{
// Subscribe to BTC
string subscribeTrade = $"{{ \"sub\": \"market.{symbol}.trade.detail\", \"id\": \"{symbol} trade\"}}";
byte[] subscribeTradeAsBytes = Encoding.UTF8.GetBytes(subscribeTrade);
ClientWebSocket.SendAsync(subscribeTradeAsBytes, WebSocketMessageType.Text, true, CancellationToken.None).Wait();
Console.WriteLine($"{subscribeTrade} sent.");
string subscribeQuote = $"{{ \"sub\": \"market.{symbol}.bbo\", \"id\": \"{symbol} bbo\"}}";
byte[] subscribeQuoteAsBytes = Encoding.UTF8.GetBytes(subscribeQuote);
ClientWebSocket.SendAsync(subscribeQuoteAsBytes, WebSocketMessageType.Text, true, CancellationToken.None).Wait();
Console.WriteLine($"{subscribeQuote} sent.");
ArraySegment<byte> bytesReceived = new ArraySegment<byte>(new byte[819200]);
//Read from WebSocket
while (ClientWebSocket.State == WebSocketState.Open)
{
WebSocketReceiveResult receiveResult = ClientWebSocket.ReceiveAsync(bytesReceived, CancellationToken.None).Result;
byte[] compressedBytes = bytesReceived.Array[..receiveResult.Count];
byte[] decompressedBytes;
//Decompress json
using (MemoryStream compressedStream = new MemoryStream(compressedBytes))
{
using (GZipStream decompressionStream = new GZipStream(compressedStream, CompressionMode.Decompress))
{
using (MemoryStream decompressedStream = new MemoryStream())
{
decompressionStream.CopyTo(decompressedStream);
decompressedBytes = decompressedStream.ToArray();
}
}
}
string json = Encoding.UTF8.GetString(decompressedBytes);
// Handle ping
if (json.Contains("ping"))
{
pings++;
string pong = json.Replace("ping", "pong");
Console.WriteLine($"{json} received");
byte[] pongAsBytes = Encoding.UTF8.GetBytes(pong);
ClientWebSocket.SendAsync(pongAsBytes, WebSocketMessageType.Text, true, CancellationToken.None).Wait();
Console.WriteLine($"{pong} sent");
Console.WriteLine($"{pings} pings received");
}
else
{
// Uncomment to see that subscription worked
//Console.WriteLine(json);
}
}
}
catch (Exception exception)
{
Console.WriteLine(exception);
Console.WriteLine($"Huobi closed WebSocket after {pings} pings.");
}
}
}
}
Here is the output of my program:
{ "sub": "market.btcusdt.trade.detail", "id": "btcusdt trade"} sent.
{ "sub": "market.btcusdt.bbo", "id": "btcusdt bbo"} sent.
{"ping":1627090272242} received
{"pong":1627090272242} sent
1 pings received
{"ping":1627090277234} received
{"pong":1627090277234} sent
2 pings received
{"ping":1627090282238} received
{"pong":1627090282238} sent
3 pings received
{"ping":1627090287239} received
{"pong":1627090287239} sent
4 pings received
{"ping":1627090292238} received
{"pong":1627090292238} sent
5 pings received
{"ping":1627090297241} received
{"pong":1627090297241} sent
6 pings received
System.AggregateException: One or more errors occurred. (The remote party closed the WebSocket connection without completing the close handshake.)
---> System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake.
at System.Net.WebSockets.ManagedWebSocket.ThrowIfEOFUnexpected(Boolean throwOnPrematureClosure)
at System.Net.WebSockets.ManagedWebSocket.EnsureBufferContainsAsync(Int32 minimumRequiredBytes, CancellationToken cancellationToken, Boolean throwOnPrematureClosure)
at System.Net.WebSockets.ManagedWebSocket.ReceiveAsyncPrivate[TWebSocketReceiveResultGetter,TWebSocketReceiveResult](Memory`1 payloadBuffer, CancellationToken cancellationToken, TWebSocketReceiveResultGetter resultGetter)
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
at System.Threading.Tasks.Task`1.get_Result()
at HuobiMarketWebSocketTest.HuobiMarketWebSocketTest.Main(String[] args) in C:\home\source\csharp\prog\HuobiMarketWebSocketTest - pong not recieved\HuobiMarketWebSocketTest\HuobiMarketWebSocketTest\HuobiMarketWebSocketTest.cs:line 156
Huobi closed WebSocket after 6 pings.