2012-04-10 3 views
5

Ich habe eine Anwendung, die ich für Windows 8/WinRT schreibe, die die StreamSocket-API verwendet, um eine Streaming-Verbindung zu einem Server zu tun. Das heißt, der Server überträgt Daten an den Client, manchmal mit Meta-Tags, und kann die Verbindung jederzeit trennen.Umgang mit WinRT StreamSocket trennt (Server- und Client-Seite)

Das Problem, das ich habe, ist, dass ich keine Ahnung habe, wie man erkennt, wenn der Server die Verbindung getrennt hat. Es scheint keine Ereignisse oder Eigenschaften in der StreamSocket-Klasse zu geben, weder in den Eingabe- oder Ausgabeströmen noch in den DataReader/DataWriter-Klassen, die irgendetwas mit dem Verbindungsstatus zu tun haben.

Darüber hinaus schlägt die DataReader-Methode ReadAsync nicht fehl, nachdem die Serverseite die Verbindung zum Client getrennt hat. Stattdessen ist die Operation erfolgreich, soweit ich das beurteilen kann, und die Daten, die sie in ihren Puffer füllt, sind nur das letzte, was der Server an sie geschickt hat (dh sie löscht nicht ihren internen Puffer, obwohl ich sehen kann, dass sie "verbraucht" hat) der Puffer bei jedem Aufruf von ReadByte). Dies geschieht für jeden weiteren Aufruf von ReadAsync - das Auffüllen des Puffers mit dem, was der Server zuletzt gesendet hat, bevor die Verbindung getrennt wurde. Hier ist eine vereinfachte Version des Codes:

public async Task TestSocketConnectionAsync() 
    { 
     var socket = new StreamSocket(); 
     await socket.ConnectAsync(new HostName(Host), Port.ToString(), 
      SocketProtectionLevel.PlainSocket); 
     var dr = new DataReader(socket.InputStream); 
     dr.InputStreamOptions = InputStreamOptions.Partial; 

     this.cts = new CancellationTokenSource(); 
     this.listenerOperation = StartListeningAsync(dr, cts); 
    } 

    public async Task StartListeningAsync(DataReader dr, CancellationTokenSource cts) 
    { 
     var token = cts.Token; 
     while (true) 
     { 
      token.ThrowIfCancellationRequested(); 
      var readOperation = dr.LoadAsync(1024); 
      var result = await readOperation; 
      if (result <= 0 || readOperation.Status != Windows.Foundation.AsyncStatus.Completed) 
      { 
       cts.Cancel(); // never gets called, status is always Completed, result always > 0 
      } 
      else 
      { 
       while (dr.UnconsumedBufferLength > 0) 
       { 
        byte nextByte = dr.ReadByte(); 

        // DriveStateMachine(nextByte); 
       } 
      } 
     } 
    } 

Antwort

9

Das heißt, die Server-Datenströme an den Client, manchmal mit Meta-Tags und jederzeit trennen. Das Problem, das ich habe, ist, dass ich keine Ahnung habe, wie man erkennt, wenn der Server die Verbindung getrennt hat.

Ein "anmutiger" Socket-Verschluss kann von der anderen Seite als 0-Längen-Lesevorgang erkannt werden. Das heißt, es verhält sich nur wie ein reguläres Ende-of-Stream.

Ein "abortive" Socket-Verschluss ist komplizierter. Sie have to send data zu erkennen, dass die andere Seite geschlossen hat, und wenn dieser Schreibvorgang fehlschlägt, sollten alle zusätzlichen Lese- oder Schreibvorgänge fehlschlagen (mit einer Ausnahme). Wenn Ihr Protokoll das Senden von Daten nicht zulässt, müssen Sie annehmen, dass die Verbindung nach Ablauf eines Zeitlimits fehlerhaft ist, und schließen Sie sie einfach. :(

Abhängig von der Anwendung „gescheiterter“ socket Verschluss kann normal - insbesondere, sehr beschäftigt Server kann geschlossen ihre Verbindungen zu klemmen geschrieben werden, weil es ihnen erlaubt, Ressourcen schneller zurückzugewinnen (die vier vermeiden -Schritt Buchse Shutdown-Handshake).

Es scheint keine Ereignisse oder Eigenschaften auf der StreamSocket Klasse, entweder seine Eingangs- oder Ausgangsströme oder auf dem Datareader/Datawriter-Klassen, die etwas mit Verbindung zu tun hat Status

DataReader/DataWriter sind nicht mit "Verbindungen" betroffen. Sie sind wirklich nur BitConverter, dieses Mal nur besser gestaltet.

Ich würde vermuten, dass der Grund StreamSocket hat keine "verbundene" Eigenschaft ist, weil Socket.Connected is nearly useless and definitely misleading.


Ich würde versuchen, StreamSocket.InputStream.ReadAsync direkt anstelle von DataReader verwenden, werden, da Sie nur Bytes ohnehin zu lesen. Es klingt, als ob Sie einen Fehler in DataReader aufgedeckt haben, den Sie auf Microsoft Connect melden sollten, wenn InputStream.ReadAsync wie erwartet funktioniert. Siehe auch this related forum post.

+1

Dies ist eine gute Information zu wissen.Vielen Dank. Es scheint, dass das DataReader.ReadAsync-Problem ein Fehler ist und es scheint, dass das entsprechende Team in Microsoft davon Kenntnis hat, also wird das hoffentlich behoben werden. In der Zwischenzeit habe ich Ihren Vorschlag, InputStream.ReadAsync auf meinem eigenen IBuffer (von WindowsRuntimeBuffer.Create) zu verwenden, versucht und es hat nicht nur funktioniert, sondern es scheint auch die Latenz um einen merklichen Betrag reduziert zu haben. –

+0

hat dieses alte Posting gefunden. @ JeremyBell was ist der User-Voice-Bug, den du über 'InputStream.ReadAsync' geöffnet hast? Ist es jetzt gelöst? Ich habe auch seltsames Verhalten in meinem Input-Stream, dass es immer wieder Antworten vom Server sammelt, die nicht da sein sollten. Ich möchte alle Daten aus dem Socket lesen, bevor ich neue Daten an den Server sende. Siehe http://stackoverflow.com/questions/27533703/how-to-read-all-the-available-data-from-a-winrt-streamsocket-and-empty-the-input?noredirect=1#comment43496033_27533703 – philk