21

I am currently looking into using websockets to communicate between a client/agent and a server, and decided to look at C# for this purpose. Although I have worked with Websockets before and C# before, this is the first time I using both together. The first attempt used the following guide: http://www.codeproject.com/Articles/618032/Using-WebSocket-in-NET-Part

public static void Main(string[] args)
{
    Task t = Echo();
    t.Wait();
}

private static async Task Echo()
{
    using (ClientWebSocket ws = new ClientWebSocket())
    {
        Uri serverUri = new Uri("ws://localhost:49889/");
        await ws.ConnectAsync(serverUri, CancellationToken.None);
        while (ws.State == WebSocketState.Open)
        {
            Console.Write("Input message ('exit' to exit): ");
            string msg = Console.ReadLine();
            if (msg == "exit")
            {
                break;
            }
            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));
        }
    }
}

Although this seems to work as expected, I was wondering if there is any way I can use the built in streams/readers in .NET with ClientWebSocket?

Seems odd to me that Microsoft has this rich well established set of stream and reader classes, but then decides to implement ClientWebSocket with only the ability to read blocks of bytes that must be handled manually.

Lets say I wanted to transfer xml, it would be easy for me to just wrap the socket stream in a XmlTextReader, but this is not obvious with ClientWebSocket.

2
  • 1
    Start using SignalR Commented Aug 17, 2016 at 20:19
  • SignalR actually has tons of problems. It has always been very unreliable. Perhaps the biggest problem that I've had with it is that you cannot upgrade your server SignalR version without forcing clients to take an update. This is not always good business. Commented Feb 11, 2019 at 22:34

2 Answers 2

3
+50

Why don't work with byte arary? What about using XmlDictionaryReader.CreateTextReader which accept byte array from System.Runtime.Serialization assembly?. Working code:

namespace XmlReaderOnByteArray
{
    using System;
    using System.Xml;

    class Program
    {
        public static void Main(string[] args)
        {
            // Some XML
            string xml = @"<?xml version=""1.0"" encoding=""UTF-8""?>
                <note>
                <to>Tove</to>
                <from>Jani</from>
                <heading>Reminder</heading>
                <body>Don't forget me this weekend!</body>
                </note>";
            // Get buffer from string
            ArraySegment<byte> arraySegment = new ArraySegment<byte>(System.Text.Encoding.UTF8.GetBytes(xml));
            // Use XmlDictionaryReader.CreateTextReader to create reader on byte array
            using (var reader = XmlDictionaryReader.CreateTextReader(arraySegment.Array, new XmlDictionaryReaderQuotas())) {
                while (reader.Read()) {
                    Console.WriteLine("{0}[{1}] => {2}", reader.Name, reader.NodeType, reader.Value);
                }
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Why is websockets providing a arraysegment rather than byte [] or even complete message when the frame is complete?
As I understand, when await ClientWebSocket.ReceiveAsync return control, you will get full result (there are no chunking). In my opinion, the main benefit of ArraySegment is preventing copying of buffer. You can find more detailed answers http://stackoverflow.com/q/4600024/5794617 and on msdn page
1

For network operations, someone has to do the work of waiting, checking, reading, waiting, understanding end of message, etc. Your example doesn't really do this, but just waits until 1024 bytes have been read and then stops.

You could implement an abstract Stream class to handle the loop which does the waiting and reading until "finished." Remember that a stream is just an abstraction of a byte-array. Also a Stream does not have the idea of asynchronous reading/writing so you would have to build that if you want it. The key here is that your Stream needs to understand the underlying bytes across the socket so that it knows when reading is finished.

4 Comments

Does this mean I need to manually read each message block by block (e.g. into a memorystream) until I find the end of message and then handle the result? If so, wouldnt it be more convenient to have a built-in method to read the message to the end, instead of guessing size of receiving buffer?
How will anyone but you know when the end of message arrives? You are building the protocol here.
Fair enough, although since ClientWebsocket does know when a message is complete, I expected it to provide some convenience methods to provide the full message. I cant see a reason why it shouldnt, since I assume most people probably works with full messages anyway.
Actually, it looks like the abstract Stream API does have async read/write methods since at least .NET 4.5.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.