NetworkStream Close bei gleichzeitigem Read
-
Hallo zusammen,
Normalerweise würde ich in diesem Problem asynchron arbeiten mit einem Timeout, doch leider geht es nicht, sprich die Möglichkeit steht nicht zur Verfügung. Auch kann ich kein Interrupt verwenden, da ich mich auf dem Compact Framework befinde.
Problem ist eigentlich ganz einfach. Ich habe von einer anderen Bibliothek einen NetworkStream. Nun lese ich aus dem Stream, doch leider ist das eine blockierende Funktion. Wenn ich nun die Verbindung wechseln will, muss ich irgendwie diese Verbindung kappen. Der Thread selber soll aber wieder verwendet werden, er holt sich die nächste Verbindung nämlich selbst. Daher kann ich
Abort
auch gleich vergessen. Nun, was bleibt mir übrig? Wenn ichClose
aufrufe, bekomme ich beimRead
eineIOException
. Dagegen hätte ich nichts einzuwenden, doch weiss ich nicht so recht, wie sicher dies ist. Welche Garantien habe ich? Oder hat vielleicht jemand noch eine andere Idee?Grüssli
-
Mir ist das Problem zwar nicht so ganz klar, aber ein paar Gedanken werde ich mal los:
- Mit NetworkStream.ReadTimeout (Default: Infinite) kann man einstellen, wielange .Read() auf Daten warten soll
- Mit NetworkStream.DataAvailable kann man vor einem Read()-Aufruf prüfen ob Daten da wären
-
geeky schrieb:
- Mit NetworkStream.ReadTimeout (Default: Infinite) kann man einstellen, wielange .Read() auf Daten warten soll
Geht nicht, weil ich auf dem Compact Framework bin. Die Property ist zwar vorhanden, wird aber laut Dokumentation nicht unterstützt.
geeky schrieb:
- Mit NetworkStream.DataAvailable kann man vor einem Read()-Aufruf prüfen ob Daten da wären
Gute Idee, geht aber leider auch nicht. Ich lese jeweils immer Zeilenweise aus. Wenn nur eine halbe Zeile ankommt, dann wird auch bis in alle Ewigkeit auf das Zeilenende gewartet.
Aber gut, ich hatte den Text etwas in Eile hingeschrieben. Ich probiere ihn nochmals zu verdeutlichen. Diesmal mit etwas "Code".
public class Server { private StreamReader m_reader; void HandleRequests(Stream stream) { m_reader = new StreamReader(stream); while(run) { String request = m_reader.ReadLine(); // ... } } void HandleConnections() { Stream stream = GetNextConnection(); // Liefert einen NetworkStream zurück. HandleRequests(stream); } void Reconnect() { // Hier kommt ein anderer Thread und will, dass die nächste Connection // behandelt wird. // Was mache ich hier, falls der Server-Thread in m_reader.ReadLine ist // und blockierend wartet? // Auf dem Compact Framework habe ich kein Interrupt zur Verfügung. // Abort will ich auch nicht, weil // 1. Wäre es womöglich gar nicht nötig, da er gerade eine Antwort // zurückschickt und nur das setzen von run auf false, würde reichen. // 2. Will ich den Thread weiterverwenden. } }
Zur Erinnerung: Ich verwende das Compact Framework.
Grüssli
-
Also, ich habe selber natürlich auch noch weitergeforscht. Ich bin aktuell auf folgendes Ergebnis gekommen, allerdings leider mit keiner 100% Garantie (nur ca. 90%, leichte Zweifel habe ich noch :)).
Wenn der Thread in
ReadLine
blockiert, dann ist er imRead
des Sockets. Wenn man auf dem StreamClose
aufruft und der NetworkStream das Socket besitzt, was man beim Konstruktor des NetworkStreams angeben kann, dann wird auch das Socket geschlossen. Falls man nicht sicher ist, ob die Bibliothek dem NetworkStream das Socket als Besitz übergibt, kann man auch direkt auf dem SocketClose
aufrufen, sofern die Möglichkeit besteht.Gut, wenn nun
Close
auf dem Socket aufgerufen wird, dann werden alle aktuellen Lese- und Schreiboperationen beendet. Dies scheint garantiert zu sein und man kann da auch mit einem anderen Thread dasClose
des Sockets aufrufen. Die Operationen geben dann einen Fehlercode zurück (also in der WinAPI/WinSocks). Dies führt in .Net zu einer IOException.Und nun das Problem, wieso ich nur zu 90% sicher bin. Meine Informationen habe ich nur aus den MSDN Foren und zum Beispiel von der Dokumentation von
closesocket
. Ich habe leider nirgends eine offizielle Dokumentierung von diesem Verhalten in .Net gefunden.
Im MSDN Forum wird zum Teil sogar davon gesprochen, dass dies das ganz normale Vorgehen sein soll.Falls jemand darüber noch mehr und bessere Informationen findet, dann immer her damit.
Grüssli