2016-08-12 17 views
15

Obecnie szukam możliwości użycia websockets do komunikacji między klientem/agentem a serwerem i postanowiłem spojrzeć na C# w tym celu. Chociaż pracowałem wcześniej z Websockets i C#, po raz pierwszy używam ich razem. Pierwsza próba używany następujący przewodnik: http://www.codeproject.com/Articles/618032/Using-WebSocket-in-NET-PartUżywanie C# ClientWebSocket ze strumieniami

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

Mimo to wydaje się działać zgodnie z oczekiwaniami, zastanawiałem się, czy jest jakiś sposób mogę korzystać z wbudowanych w potokach/czytelników w .NET z ClientWebSocket?

Wydaje mi się dziwne, że Microsoft ma bogaty, dobrze znany zestaw klas strumienia i czytnika, ale następnie decyduje się na wdrożenie ClientWebSocket z możliwością odczytu bloków bajtów, które muszą być obsługiwane ręcznie.

Powiedzmy, że chciałem przenieść xml, łatwo byłoby mi po prostu opakować strumień gniazd w XmlTextReader, ale nie jest to oczywiste w ClientWebSocket.

+1

Rozpocznij używanie SignalR –

Odpowiedz

2

Dlaczego nie pracować z bajtem? A co z użyciem 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); 
       } 
      } 
     } 
    } 
} 
+0

Dlaczego websockets dostarcza segmentse zamiast bajtu [], a nawet kompletny komunikat, gdy ramka jest kompletna? – agnsaft

+0

Jak rozumiem, gdy oczekuję [ClientWebSocket.ReceiveAsync] (https://msdn.microsoft.com/en-us/library/system.net.websockets.clientwebsocket.receiveasync (v = vs.110) .aspx) kontrola powrotu , otrzymasz pełny wynik (nie ma chunkingu). Moim zdaniem główną zaletą ArraySegment jest zapobieganie kopiowaniu bufora. Możesz znaleźć bardziej szczegółowe odpowiedzi [http://stackoverflow.com/q/4600024/5794617](http://stackoverflow.com/q/4600024/5794617) i [na stronie msdn] (https://msdn.microsoft .com/en-us/library/1hsbd92d (v = vs.110) .aspx # Anchor_7) –

1

przypadku operacji sieciowych, ktoś musi wykonywać pracę czekając, sprawdzając, czytanie, czekając, rozumiejąc koniec wiadomości, itd. Twój przykład nie naprawdę to zrobić, ale po prostu czeka aż 1024 bajtów zostały przeczytane, a następnie przestają.

Można zaimplementować abstrakcyjną klasę Stream, aby obsłużyć pętlę, która oczekuje i czyta do "ukończenia". Pamiętaj, że strumień jest po prostu abstrakcją tablicy bajtów. Również strumień nie ma idei asynchronicznego odczytu/zapisu, więc musiałbyś to zbudować, jeśli chcesz. Kluczem jest tutaj to, że Twój strumień musi zrozumieć podstawowe bajty w całym gnieździe, aby wiedział, kiedy skończy się czytanie.

+0

Czy to oznacza, że ​​muszę ręcznie czytać każdy blok wiadomości przez blok (np. do memorystream), aż znajdę koniec wiadomości i a następnie obsłużyć wynik? Jeśli tak, czy nie byłoby wygodniej mieć wbudowaną metodę odczytu komunikatu do końca, zamiast zgadywania rozmiaru bufora odbiorczego? – agnsaft

+0

W jaki sposób ktoś oprócz Ciebie będzie wiedział, kiedy nadejdzie koniec wiadomości? Budujesz tutaj protokół. –

+0

Wystarczająco uczciwe, chociaż od czasu, gdy ClientWebsocket wie, kiedy wiadomość jest kompletna, oczekiwałem, że zapewni ona pewne dogodne metody dostarczania pełnej wiadomości. Nie widzę powodu, dla którego to nie powinno, ponieważ zakładam, że większość ludzi prawdopodobnie i tak pracuje z pełnymi wiadomościami. – agnsaft