0

The example shown on the following page doesn't work: Using c# ClientWebSocket with streams

It hangs on the following line:

await ws.ConnectAsync(serverUri, CancellationToken.None);

It appears the connection is not made.

Please indicate the simplest modification to make the following code work. I do not wish to use any 3rd party tools or libraries.

private static async Task DoClientWebSocket()
{
    using (ClientWebSocket ws = new ClientWebSocket())
    {
        Uri serverUri = new Uri("wss://echo.websocket.org/");
        await ws.ConnectAsync(serverUri, CancellationToken.None);
        while (ws.State == WebSocketState.Open)
        {
            string msg = "hello123";
            ArraySegment<byte> bytesToSend = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msg));
            await ws.SendAsync(bytesToSend, WebSocketMessageType.Text, true, CancellationToken.None);
            ArraySegment<byte> bytesReceived = new ArraySegment<byte>(new byte[1024]);
            WebSocketReceiveResult result = await ws.ReceiveAsync(bytesReceived, CancellationToken.None);
            Console.WriteLine(Encoding.UTF8.GetString(bytesReceived.Array, 0, result.Count));
        }
    }
}
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
Tester
  • 117
  • 1
  • 1
  • 9
  • If I go to http://websocket.org/echo.html, and look a the example, the URI is `ws://echo.websocket.org`, not `wss://echo.websocket.org/`. Oops, I see both URIs. – Flydog57 Feb 11 '20 at 16:28
  • I tried both ws: and wss:. Both worked in javascript, neither worked in c#. – Tester Feb 11 '20 at 16:34
  • You are making it very difficult. The default request headers in c# are not the same as other applications. Usually to get code to work you have to add missing headers or modify the default headers. The best way of solving issue is to compare java or that works with the non working application using a sniffer. Compare the first request with java and c#. – jdweng Feb 11 '20 at 17:00
  • No headers were added in javascript: websocket = new WebSocket(wsUri); What headers do I have to add in C#? – Tester Feb 11 '20 at 17:17

1 Answers1

7

You are correct. You don't need to add any header in order to use wss://echo.websocket.org/. Your code run just fine at my end. But I'll suggest one improvement to include timeout for your ConnectAsync, SendAsync and ReceiveAsync calls so that it do not get stuck for long.

I have restricted code to call SendAsync to just 5 times so that its easier to verify output.

[Edited:] Include logic to receive complete response by calling `ReceiveAsync multiple times.

private static async Task DoClientWebSocket()
{
    using (ClientWebSocket ws = new ClientWebSocket())
    {
        Uri serverUri = new Uri("wss://echo.websocket.org/");

        //Implementation of timeout of 5000 ms
        var source = new CancellationTokenSource();
        source.CancelAfter(5000);

        await ws.ConnectAsync(serverUri, source.Token);
        var iterationNo = 0;
        // restricted to 5 iteration only
        while (ws.State == WebSocketState.Open && iterationNo++ < 5)
        {
          string msg = "hello0123456789123456789123456789123456789123456789123456789";
          ArraySegment<byte> bytesToSend =
                      new ArraySegment<byte>(Encoding.UTF8.GetBytes(msg));
          await ws.SendAsync(bytesToSend, WebSocketMessageType.Text,
                               true, source.Token);
          //Receive buffer
          var receiveBuffer = new byte[200];
          //Multipacket response
          var offset = 0;
          var dataPerPacket = 10; //Just for example
          while (true)
          {
              ArraySegment<byte> bytesReceived =
                        new ArraySegment<byte>(receiveBuffer, offset, dataPerPacket);
              WebSocketReceiveResult result = await ws.ReceiveAsync(bytesReceived,
                                                            source.Token);
              //Partial data received
              Console.WriteLine("Data:{0}",
                               Encoding.UTF8.GetString(receiveBuffer, offset,
                                                            result.Count));
              offset += result.Count;
              if (result.EndOfMessage)
                    break;
            }
            Console.WriteLine("Complete response: {0}",
                                Encoding.UTF8.GetString(receiveBuffer, 0,
                                                            offset));
        }
    }
}


static void Main(string[] args)
{
    var taskWebConnect = Task.Run(() => DoClientWebSocket());

    taskWebConnect.Wait();
}

Output on command prompt:

Data:hello01234
Data:5678912345
Data:6789123456
Data:7891234567
Data:8912345678
Data:9123456789
Complete response: hello0123456789123456789123456789123456789123456789123456789
MKR
  • 19,739
  • 4
  • 23
  • 33
  • @Tester Glad to know. Happy to help. You can accept answer by clicking on `Tick` symbol in left of answer window. – MKR Feb 12 '20 at 17:30
  • Now I need to retrieve 100k from a different WebSocket. When I increase the size of 'ArraySegment(new byte' to 1024000, it still only retrieves 12K. Can you modify your code example to retrieve up to 1MB? – Tester Feb 12 '20 at 18:09
  • @Tester You can use `EndOfMessage` property of response received from `ReceiveAsync` to read multiple times until all data has been read. I'll update the code to address it. – MKR Feb 13 '20 at 12:08