2009-08-27 5 views
31

Wenn ich nur zu einem Socket in einem Ausgabestrom schreibe, wird es jemals blockieren? Nur Lesevorgänge können blockieren, oder? Jemand hat mir gesagt, dass Schreibvorgänge blockieren können, aber ich sehe nur eine Zeitüberschreitung für die Lesemethode eines Sockets - Socket.setSoTimeout().Java-Socket/Ausgabe Stream schreibt: Blockieren sie?

Es macht keinen Sinn für mich, dass ein Schreiben blockieren könnte.

+0

Die Tatsache, dass es nicht eine Timeout-Funktion ist nicht selbst ein Hinweis darauf, dass es nicht blockiert. Ein Hinweis darauf, dass dies der Fall ist, ist das Fehlen eines Rückgabewerts: Wenn er nicht blockiert wird, warum gibt er dann nicht die Anzahl der tatsächlich geschriebenen Bytes zurück? Ein weiterer Hinweis wird gegeben, indem Sie es einfach versuchen. – EJP

Antwort

45

Ein Schreiben auf einem Socket kann auch blockieren, vor allem, wenn es sich um einen TCP-Socket handelt. Das Betriebssystem puffert nur eine bestimmte Menge nicht übertragener (oder übertragener, aber nicht quittierter) Daten. Wenn Sie etwas schneller schreiben, als die Remote-Anwendung es lesen kann, wird der Socket schließlich gesichert und Ihre write-Aufrufe werden blockiert.

Reaktion auf diese Folgefragen:

So gibt es einen Mechanismus ein Timeout für diese Einstellung vornehmen? Ich bin mir nicht sicher, was Verhalten es hätte ... vielleicht Daten wegwerfen, wenn Puffer voll sind? Oder möglicherweise ältere Daten im Puffer löschen?

Es gibt keinen Mechanismus zum Festlegen eines Schreib-Timeouts auf einem java.net.Socket. Es gibt eine Socket.setSoTimeout() Methode, aber es betrifft accept() und read() Anrufe ... und nicht write() Anrufe. Offenbar können Sie Schreib-Timeouts erhalten, wenn Sie NIO, nicht-blockierenden Modus und einen Selektor verwenden, aber das ist nicht so nützlich, wie Sie sich vorstellen können.

Ein korrekt implementierter TCP-Stack verwirft keine gepufferten Daten, es sei denn, die Verbindung wird geschlossen. Wenn Sie jedoch eine Schreib-Zeitüberschreitung erhalten, ist es unsicher, ob die Daten, die sich derzeit in den Puffern auf Betriebssystemebene befinden, am anderen Ende empfangen wurden oder nicht. Das andere Problem ist, dass Sie nicht wissen, wie viel von den Daten von Ihrem letzten write tatsächlich in TCP-Stapelpuffer des Betriebssystems übertragen wurde. Wenn ein Protokoll der Anwendungsebene zum erneuten Synchronisieren des Streams * nicht vorhanden ist, ist die einzige sichere Maßnahme nach einem Timeout unter write das Herunterfahren der Verbindung.

Wenn Sie dagegen einen UDP-Socket verwenden, werden die Anrufe write() nicht für längere Zeit blockiert. Der Nachteil besteht jedoch darin, dass im Falle von Netzwerkproblemen oder wenn die Remote-Anwendung nicht mithalten kann, Nachrichten ohne Benachrichtigung an beide Enden auf dem Boden gelöscht werden. Darüber hinaus stellen Sie möglicherweise fest, dass Nachrichten manchmal nicht ordnungsgemäß an die Remoteanwendung übermittelt werden. Es liegt an Ihnen (dem Entwickler), sich mit diesen Problemen zu befassen.

* Theoretisch ist das möglich, aber für die meisten Anwendungen macht es keinen Sinn, einen zusätzlichen Resynchronisationsmechanismus zusätzlich zu einem bereits zuverlässigen (zu einem bestimmten) TCP/IP-Stream zu implementieren. Und wenn es Sinn macht, müssten Sie auch mit der Möglichkeit umgehen, dass die Verbindung geschlossen wird ... also wäre es einfacher, davon auszugehen, dass es geschlossen ist.

+0

Also gibt es einen Mechanismus, um eine Zeitüberschreitung dafür einzustellen? Ich bin mir nicht sicher, welches Verhalten es hätte ... vielleicht Daten wegwerfen, wenn Puffer voll sind? Oder möglicherweise ältere Daten im Puffer löschen? – jbu

+0

Gibt es eine Möglichkeit, dies zum Testen zu reproduzieren? Ich möchte, dass sich meine Anwendung davon erholen kann. Dazu brauche ich – Zamir

+0

AFAIK testen, gibt es keinen allgemeinen Weg. Aber abhängig von der Art Ihrer Anwendung (z. B. was es spricht) gibt es viele Möglichkeiten. Stellen Sie eine neue Frage ... und seien Sie spezifisch. –