2015-02-18 7 views
5

Ich habe eine Client-Anwendung, die mit einem QEMU-Prozess über einen QMP Unix-Domain-Socket kommuniziert. Manchmal, nachdem der Client clos() für die Socket-Verbindung aufgerufen hat, zeigt 'netstat -ap unix' immer noch den Status CONNECTED an. Ich überprüfe den Rückgabewert des Aufrufs close() und es wird erfolgreich mit einem Wert von 0 zurückgegeben, aber die Verbindung scheint immer noch zu bleiben.UNIX-Domänen-Socket nicht geschlossen nach close()

Da QMP mehrere Verbindungen an seinem Socket nicht wirklich unterstützt, schlagen alle nachfolgenden Aufrufe für die Verbindung zum Socket fehl, da sie unbegrenzt auf das Schließen der Verbindung warten.

Gibt es eine Möglichkeit, aus dem Code zu überprüfen, dass der Socket wirklich geschlossen ist, und gibt es eine Möglichkeit, den Socket zum Schließen zu zwingen?

+1

Es klingt, als ob der QEMU-Server-Prozess den Inhalt des letzten send() nicht vollständig gelesen hat. Was passiert, wenn Sie anstelle von Domain-Sockets TCP verwenden? Gibt es einen Unterschied im Verhalten? – user590028

+0

Das Verhalten, das ich gerade beschrieben habe, ist nicht 100% reproduzierbar, und leider ist die Verwendung von TCP für mich keine Option. – mgamal

+0

Können wir die Ausgabe von netstat -ap sehen? – user590028

Antwort

-1

Sie könnten SO_LINGER einfach über die Option setsockopt (2) mit einem Timeout von 0 versuchen. Auf diese Weise wird beim Schließen des Sockets zwangsweise ein RST gesendet, anstatt in das FIN/ACK-Schließverhalten zu wechseln.

Der Zweck der SO_LINGER-Option besteht darin, zu steuern, wie der Socket heruntergefahren wird, wenn die Funktion close (2) aufgerufen wird. Diese Option gilt nur für verbindungsorientierte Protokolle wie TCP.

Das Standardverhalten des Kernels besteht darin, dass die Funktion close (2) sofort zum Aufrufer zurückkehren kann. Alle nicht gesendeten TCP/IP-Daten werden nach Möglichkeit übermittelt und zugestellt, es wird jedoch keine Gewährleistung übernommen. Da der Aufruf von close (2) die Steuerung sofort an den Aufrufer zurückgibt, kann die Anwendung nicht wissen, ob das letzte Bit der Daten tatsächlich geliefert wurde.

Die SO_LINGER-Option kann am Socket aktiviert werden, damit die Anwendung beim Schließen (2) blockiert, bis alle endgültigen Daten an das Remote-Ende gesendet wurden. Außerdem wird dadurch sichergestellt, dass beide Seiten eine normale Socket-Abschaltung quittiert haben. Andernfalls tritt das angegebene Zeitlimit für die Option auf und ein Fehler wird an die aufrufende Anwendung zurückgegeben.

Ein letztes Szenario kann durch Verwendung verschiedener SO_LINGER-Optionswerte angewendet werden. Wenn die aufrufende Anwendung die Kommunikation sofort abbrechen möchte, können in der Verweilzeitstruktur entsprechende Werte eingestellt werden. Dann wird ein Anruf zum Schließen (2) einen Abbruch der Kommunikationsverbindung initiieren, alle anstehenden Daten verwerfen und den Socket sofort schließen.

+0

geschlossen haben. Es "garantiert Anrufern nicht, dass beide Seiten eine normale Abschaltung quittiert haben". Es versichert dem Anrufer nur, dass alle ausstehenden Daten gesendet wurden. – EJP

+0

Der fragliche Socket ist ein dateibasierter UNIX-Domain-Socket, daher bin ich mir nicht sicher, ob SO_LINGER hier helfen soll. – mgamal

0

Haben Sie versucht, den Sockel vom anderen Ende zu schließen? Es ist asynchron, aber es gibt beiden Seiten eine Chance, die Socket-Schließung zu gewährleisten.

Sie können einen Schließbefehl an den Listener am anderen Ende senden und den Socket recyceln lassen. Wenn der Sockel geschlossen wird, solltest du ein SIGPIPE bekommen. Fange den SIGPIPE und schließe dein Ende des Sockets. Wenn Sie damit eine EPIPE erreichen, ignorieren Sie sie. Das bedeutet nur, dass Sie bereits über den Socket-Verschluss informiert wurden.

+0

QEMU macht das schon. – mgamal

1

Es könnte sein, dass der Dateideskriptor dup ed, fork ed oder durchgesickert wurde.

Rufen Sie shutdown(sock, SHUT_RDWR) darauf an, um die Verbindung sicher vor close ing zu schließen.

+0

Werde das versuchen. Danke – mgamal

+0

Ich bekam immer -EAGAIN, wenn ich versuchte, an einen neuen Socket zu verbinden, wenn eine andere Verbindung verweilte. Nachdem ich shutdown() benutzt habe, konnte ich tatsächlich() mit dem Socket verbinden, ohne -EAGAIN zu erhalten, selbst wenn ein anderer Socket nicht geschlossen ist() d – mgamal

Verwandte Themen