2016-05-03 18 views
0

Ich habe ein paar Fragen ähnlich gesehen, aber bis jetzt habe ich keine wirkliche Lösung gesehen, die für die UWP-Plattform funktioniert.DataReader von SocketStream für UWP App

Ich verbinde mich mit einigen UPnP-Geräten im Netzwerk, die JSON zurück über Port 1255 senden. Ich habe die erste Verbindung funktioniert und die Sendeanforderung, die die Geräte anfordert, mir einige Informationen zu senden.

StreamSocket socket; 
using (socket = new StreamSocket()) 
{ 
    hostName = new HostName("192.168.0.nnn"); 
    await socket.ConnectAsync(hostName, "1255"); 
    //Code that does the request for info 
    await this.read(); 
} 

public async Task<String> read() 
{ 
    string runStr = ""; 
    uint inBufferCnt = 0; 

    using (reader = new DataReader(socket.InputStream)) 
    { 
     reader.InputStreamOptions = Windows.Storage.Streams.InputStreamOptions.ReadAhead; 
     reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8; 
     reader.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian; 

     inBufferCnt = await reader.LoadAsync(256); //InBuffer is always 256, 
      //even if there is more data waiting. If I put a task.delay in it will always return 256 

     while (reader.UnconsumedBufferLength > 0) 
     { 
      var iRead = reader.ReadString(reader.UnconsumedBufferLength); 
      runStr = runStr + iRead; 
      inBufferCnt = await reader.LoadAsync(64); //always hangs here. 
       //Even if I reduce to 1, it will sit waiting for new data 
     } 
... 

Alles funktioniert gut, bis zum letzten LoadAsync. Solange Daten im Stream vorhanden sind, werden sie, solange sie weniger als 64 Byte umfassen, um die While-Schleife herumgespielt. Wenn es weniger als dieses tho gibt, dann sitzt es einfach da und wartet auf mehr Daten. Also könnten 50 Bytes im Puffer liegen, die ich nicht bekommen kann. Im obigen Beispiel ist der inBufferCnt immer die genaue Größe des an LoadAsync übergebenen Wertes.

Ich habe verschiedene Dinge versucht, z. B. das Hinzufügen eines Timeouts, aber ich kann nicht auf irgendetwas zugreifen, nachdem die Ausnahme ausgelöst wurde, also weiß ich immer noch nicht, wie viele Daten im Stream sind.

CancellationTokenSource cts = new CancellationTokenSource(); 
cts.CancelAfter(5000); 
... 
inBufferCnt = await reader.LoadAsync(64).AsTask(cts.Token); 

Ich habe keine Ahnung, wie viele Daten Ich werde von dem Gerät zurück, habe ich keinerlei Kontrolle über die Gerätekommunikation (andere als Info anfordern). Ich glaube, ich habe die Hälfte des Webs gelesen, während ich nach einer Lösung suche, aber ich kann nichts finden, was sich direkt auf dieses spezielle Problem bezieht.

Also lautet die Hauptfrage: "Wie soll man aus dem Socket-Stream lesen und dann, wenn es keine weiteren Daten gibt (zu diesem Zeitpunkt), einfach zurückgeben, was im aktuellen Stream sitzt in dem Puffer zu lesenden warten.

Hilfe ...

Antwort

-1

ich habe keine Ahnung, wie viele Daten werde ich von dem Gerät zurück, habe ich keinerlei Kontrolle über die Gerätekommunikation (andere als zu Informationen anfordern) Die Hauptfrage ist also: "Wie soll man aus dem Socket Stream lesen und wenn dann keine Daten mehr (zu diesem Zeitpunkt) vorliegen, einfach wha zurückgeben t sitzt im aktuellen Strom. Es könnte irgendeine Größe in dem Puffer verbleiben, der darauf wartet, gelesen zu werden.

Nach Ihrer Beschreibung, habe ich für Sie eine Lösung gefunden:

zuerst die read options für den Eingangsstrom zu Teil.

reader.InputStreamOptions = Windows.Storage.Streams.InputStreamOptions.Partial; 

Auf diese Weise lesen die asynchrone Operation abgeschlossen, wenn ein oder mehrere Bytes verfügbar ist. So der asynchrone Lesevorgang sitzt und wartet auf neue Daten nur, wenn es keine ist Bytes verfügbar ist, dann können Sie hinzufügen ein Timeout, um diese Situation zu behandeln, wie Sie oben erwähnt haben.

CancellationTokenSource cts = new CancellationTokenSource(); 
cts.CancelAfter(5000); 
... 
inBufferCnt = await reader.LoadAsync(sizeToReadEachTime).AsTask(cts.Token); 

Es folgt der Beispielcode ich überprüft haben:

public async Task<String> read() 
{ 
    string runStr = ""; 
    uint inBufferCnt = 0; 
    //size of bytes to load each time. 
    uint sizeToReadEachTime = 256; 
    CancellationTokenSource cts = new CancellationTokenSource(); 
    //set timeout here. 
    cts.CancelAfter(5000); 

    using (reader = new DataReader(socket.InputStream)) 
    { 
     //set the read options for the input stream to Partial. 
     reader.InputStreamOptions = Windows.Storage.Streams.InputStreamOptions.Partial; 
     reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8; 
     reader.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian; 

     while (true) 
     { 
      try 
      { 
       //add a timeout for the asynchronous load operation. 
       inBufferCnt = await reader.LoadAsync(sizeToReadEachTime).AsTask(cts.Token); 
       runStr += reader.ReadString(inBufferCnt); 
      } 
      catch (System.Threading.Tasks.TaskCanceledException) 
      { 
       //load operation will get timeout only when there is no data available. 
       cts.Dispose(); 
       break; 
      } 
     } 

     reader.DetachStream(); 
    } 
    return runStr; 
} 
+0

Vielen Dank für die Antwort, aber das Problem, das ich mit diesem Ansatz zu bekommen, ist, dass, wenn gab es Daten in dem Strom, aber nicht genug, um füllen Sie die gesamte sizeToReadEachTime, und wenn die Ausnahme auftritt, können Sie immer noch nicht auf die Daten zugreifen, ohne die Variable auf eine noch niedrigere Zahl zu verringern. Ich habe es geschafft, die Daten zu bekommen, indem ich den Wert auf 1 reduziere und dann die Daten mehr auswertet, dann kombiniert mit dem Ausnahme-Timeout weiß ich, dass ich alle Daten habe. Aber das scheint eine wirklich miese Art zu sein. IMO die von LoadAsync zurückgegebene uint sollte die Größe dessen zurückgeben, was tatsächlich im Puffer ist – MikeyTT

+0

Sie sind willkommen :) Und ich weiß genau, was Ihr Problem ist. Also sagte ich, dass Sie ** Leseoption ** für den Eingabestream auf ** Teil ** am Anfang meiner Antwort setzen müssen. Auf diese Weise gibt die von LoadAsync zurückgegebene Uint die Größe dessen zurück, was sich tatsächlich im Puffer befindet, selbst wenn Daten im Stream vorhanden waren, aber nicht genug, um die gesamte sizeToReadEachTime zu füllen. Alle Daten werden abgerufen, bevor die Ausnahme auftritt. Die Ausnahme tritt nur auf, wenn keine Daten im Stream vorhanden sind. Sie müssen also den Wert nicht auf eine noch niedrigere Zahl oder auf 1 in meiner obigen Lösung reduzieren. –

+0

Ich hatte ursprünglich die Partial-Option verwendet, und ich denke, ich habe den Großteil des Code-Snippets von hier: http://donatas.xyz/streamsocket-tcpip-client.html. Aber ich habe festgestellt, dass die Uint immer die Größe des Wertes hat, den du an ihn übergibst, und er hing immer an der LoadAsync, wenn weniger Daten zur Verfügung standen. Ich werde es später in der Woche nochmal versuchen, wenn ich wieder an meinem Dev-Arbeitsplatz bin. Ich glaube nicht, dass ich die Absage auch teilweise versucht habe, also werde ich mich ärgern, wenn das klappt;) – MikeyTT