Использование С# ClientWebSocket с потоками

В настоящее время я изучаю использование websockets для связи между клиентом/агентом и сервером и решил посмотреть на С# для этой цели. Хотя я уже работал с Websockets раньше и С#, это первый раз, когда я использую оба вместе. Первая попытка использовала следующее руководство: 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));
        }
    }
}

Хотя это работает так, как ожидалось, мне было интересно, есть ли способ использовать встроенные потоки/чтения в .NET с ClientWebSocket?

Мне кажется странным, что у Microsoft есть этот богатый, хорошо установленный набор потоков и классов читателей, но затем решает внедрить ClientWebSocket только с возможностью читать блоки байтов, которые нужно обрабатывать вручную.

Предположим, что я хотел перенести xml, мне было бы просто просто переносить поток сокета в XmlTextReader, но это не очевидно с ClientWebSocket.

Ответы

Ответ 1

Почему бы не работать с байтом arary? Как насчет использования XmlDictionaryReader.CreateTextReader, который принимает массив байтов из сборки System.Runtime.Serialization?. Рабочий код:

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);
                }
            }
        }
    }
}

Ответ 2

Для сетевых операций кто-то должен выполнять работу по ожиданию, проверке, чтению, ожиданию, пониманию конца сообщения и т.д. Ваш пример на самом деле этого не делает, а просто ждет, пока не будет прочитано 1024 байта, а затем остановится,

Вы можете реализовать абстрактный класс Stream для обработки цикла, который выполняет ожидание и чтение до "завершено". Помните, что поток - это просто абстракция байтового массива. Также Stream не имеет идеи асинхронного чтения/записи, поэтому вам нужно будет построить это, если хотите. Ключевым моментом здесь является то, что ваш поток должен понимать базовые байты через сокет, чтобы он знал, когда чтение завершено.