Wie finde ich den Socket-Verbindungsstatus in C?

Lesezeit: 6 Minuten

Benutzeravatar von Blacklabel
Schwarze Beschriftung

Ich habe eine TCP-Verbindung. Der Server liest nur Daten vom Client. Wenn nun die Verbindung unterbrochen wird, erhält der Client eine Fehlermeldung, während er die Daten in die Pipe schreibt (gebrochene Pipe), aber der Server lauscht immer noch auf dieser Pipe. Kann ich irgendwie feststellen, ob die Verbindung UP ist oder nicht?

  • Ich denke, Sie sollten klären, ob Sie für Windows oder Linux/Unix entwickeln.

    – nairdaen

    10. November 2010 um 7:14 Uhr

  • Wenn Sie Ergebnisse mit einem Fehler senden, sollten Sie zuerst prüfen, um welchen Fehler es sich tatsächlich handelt, und dann entscheiden, ob es sich um einen behebbaren Fehler handelt (könnte er sich vielleicht selbst beheben?) oder ob dies bedeutet, dass Ihre Verbindung mit Sicherheit tot ist. Und wenn es sicher tot ist, schließen Sie die Steckdose. Wenn Sie immer noch Datenverkehr durchlassen können, sieht die andere Seite, dass der Socket geschlossen wurde. Wenn Sie keinen Verkehr durchbringen können, sind Sie sowieso verloren. In diesem Fall kann die andere Seite nur etwas bemerken, indem sie selbst etwas sendet, das eine Antwort auslösen sollte, und wenn es keine solche Antwort gibt, ist die andere Seite tot.

    – Mecki

    18. Juli 2017 um 15:57 Uhr

Benutzeravatar von Simone
Simone

Sie könnten getsockopt wie folgt aufrufen:

int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt (socket_fd, SOL_SOCKET, SO_ERROR, &error, &len);

So testen Sie, ob der Socket aktiv ist:

if (retval != 0) {
    /* there was a problem getting the error code */
    fprintf(stderr, "error getting socket error code: %s\n", strerror(retval));
    return;
}

if (error != 0) {
    /* socket has a non zero error status */
    fprintf(stderr, "socket error: %s\n", strerror(error));
}

  • Es wird jedoch keine stillschweigend defekte Steckdose erkennen. Ein häufiges Szenario ist, dass ein NAT-Gateway die Verbindung zwischenzeitlich abschaltet (und niemand benachrichtigt wird) – um dies zu erkennen, müssen Sie, wie andere gesagt haben, regelmäßig etwas senden, indem Sie entweder eine Form von Heartbeats in Ihrem Anwendungsprotokoll implementieren oder Verwenden Sie zumindest TCP_KEEPALIVE

    – Nr

    10. November 2010 um 8:15 Uhr

  • jeder fragt sich, denke ich SOL_SOCKET steht für ‘socket option level: socket’ und SO_ERROR ist der letzte Fehlercode auf dem Socket.

    – n611x007

    30. August 2013 um 12:05 Uhr

  • Dies gibt nur den letzten Fehler zurück. Es erkennt keine anstehenden Fehler.

    – Benutzer207421

    20. Dezember 2015 um 6:40 Uhr

  • ofc erkennt keine Fehler, die noch nicht aufgetreten sind, es ist keine Zeitmaschine

    – Hansenrik

    5. März 2016 um 12:33 Uhr

  • strerror(retval) scheint zumindest unter Linux falsch zu sein. Die Manpage für getsockopt sagt: “Bei Erfolg wird Null zurückgegeben. Bei einem Fehler wird -1 zurückgegeben und errno wird entsprechend festgelegt”. Also sollte es strerror(errno) sein

    – Michail Kagalenko

    28. November 2016 um 13:45 Uhr


Benutzeravatar von Chris Becke
Chris Becke

Die einzige Möglichkeit, zuverlässig zu erkennen, ob ein Socket noch verbunden ist, besteht darin, regelmäßig zu versuchen, Daten zu senden. Es ist normalerweise bequemer, ein Ping-Paket auf Anwendungsebene zu definieren, das die Clients ignorieren, aber wenn das Protokoll bereits ohne eine solche Fähigkeit spezifiziert ist, sollten Sie in der Lage sein, TCP-Sockets so zu konfigurieren, dass Sie dies tun können, indem Sie die SO_KEEPALIVE Steckdosenoption. Ich habe auf die Winsock-Dokumentation verlinkt, aber die gleiche Funktionalität sollte auf allen BSD-ähnlichen Socket-Stacks verfügbar sein.

  • Danke für deine Zeit. Ich habe die Option SO_KEEPALIVE in Betracht gezogen, aber die Standardzeit zum Aktivieren von KeepAlive-Sonden beträgt unter Linux 2 Stunden. Wenn ich dies auf Sekunden reduziere, könnten andere Anwendungen betroffen sein. Ich werde es trotzdem versuchen 🙂

    – Schwarze Beschriftung

    10. November 2010 um 8:44 Uhr

  • Aus diesem Grund ist es üblich, auf ein Ping-Paket auf Anwendungsebene zurückzugreifen, das der Server senden kann, wenn die Verbindung für einige Zeit ruhig war. Wenn Sie – wie bei http – keine Daten senden können, ohne eine Client-Anfrage zu erhalten, haben Sie keine andere Wahl, als Verbindungen zu schließen, die “zu lange” still waren, und sich darauf zu verlassen, dass die Clients bei Bedarf erneut eine Verbindung herstellen.

    – Chris Becke

    10. November 2010 um 9:41 Uhr

  • Mit @Blacklabel Linux (und anderen) können Sie das Keepalive-Timeout pro Socket festlegen, siehe die Socket-Option TCP_KEEPIDLE in man 7 tcp

    – Nr

    10. November 2010 um 20:12 Uhr

Die TCP-Keepalive-Socket-Option (SO_KEEPALIVE) würde in diesem Szenario helfen und den Server-Socket im Falle eines Verbindungsverlusts schließen.

  • Es würde nichts schließen. Beim nächsten Senden oder Empfangen würde es einen Fehler geben, aber der Socket bleibt offen.

    – Benutzer207421

    20. Dezember 2015 um 6:34 Uhr

Benutzeravatar von yanpas
Yanpas

Es gibt eine einfache Möglichkeit, den Socket-Verbindungsstatus über zu überprüfen poll Anruf. Zuerst müssen Sie Socket abfragen, ob dies der Fall ist POLLIN Veranstaltung.

  1. Wenn Socket nicht geschlossen ist und dann Daten zu lesen sind read wird mehr als null zurückgeben.
  2. Wenn es keine neuen Daten auf dem Socket gibt, dann POLLIN wird auf 0 Zoll gesetzt revents
  3. Wenn Socket dann geschlossen ist POLLIN Flag wird auf eins gesetzt und read gibt 0 zurück.

Hier ist ein kleiner Codeschnipsel:

int client_socket_1, client_socket_2;
if ((client_socket_1 = accept(listen_socket, NULL, NULL)) < 0)
{
    perror("Unable to accept s1");
    abort();
}
if ((client_socket_2 = accept(listen_socket, NULL, NULL)) < 0)
{
    perror("Unable to accept s2");
    abort();
}
pollfd pfd[]={{client_socket_1,POLLIN,0},{client_socket_2,POLLIN,0}};
char sock_buf[1024]; 
while (true)
{
    poll(pfd,2,5);
    if (pfd[0].revents & POLLIN)
    {
        int sock_readden = read(client_socket_1, sock_buf, sizeof(sock_buf));
        if (sock_readden == 0)
            break;
        if (sock_readden > 0)
            write(client_socket_2, sock_buf, sock_readden);
    }
    if (pfd[1].revents & POLLIN)
    {
        int sock_readden = read(client_socket_2, sock_buf, sizeof(sock_buf));
        if (sock_readden == 0)
            break;
        if (sock_readden > 0)
            write(client_socket_1, sock_buf, sock_readden);
    }
}

Ich hatte ein ähnliches Problem. Ich wollte wissen, ob der Server mit dem Client oder der Client mit dem Server verbunden ist. In solchen Fällen kann der Rückgabewert der Funktion recv nützlich sein. Wenn der Socket nicht verbunden ist, werden 0 Bytes zurückgegeben. Dadurch habe ich die Schleife gebrochen und musste keine zusätzlichen Threads von Funktionen verwenden. Sie können dies auch verwenden, wenn Experten der Meinung sind, dass dies die richtige Methode ist.

  • Wenn die Verbindung besteht gescheitert Es wird nicht 0 zurückgegeben, es wird für immer blockiert oder bis das Lese-Timeout abgelaufen ist, falls es eines gibt. 0 bedeutet geordnetes Trennen, nicht z. B. Kabelziehen.

    – Benutzer207421

    6. März 2020 um 7:43 Uhr

Benutzeravatar von bem22
bem22

Sehr einfach, wie in der abgebildet Empf.

Um dies zu überprüfen, möchten Sie mit 1 Byte aus dem Socket lesen MSG_PEEK und MSG_DONT_WAIT. Dadurch werden keine Daten aus der Warteschlange entfernt (PEEK) und die Operation ist nicht blockierend (DONT_WAIT)

while (recv(client->socket,NULL,1, MSG_PEEK | MSG_DONTWAIT) != 0) {
    sleep(rand() % 2); // Sleep for a bit to avoid spam
    fflush(stdin);
    printf("I am alive: %d\n", socket);
}

// When the client has disconnected, this line will execute
printf("Client %d went away :(\n", client->socket);

Beispiel gefunden hier.

  • Wenn die Verbindung besteht gescheitert Es wird nicht 0 zurückgegeben, es wird für immer blockiert oder bis das Lese-Timeout abgelaufen ist, falls es eines gibt. 0 bedeutet geordnetes Trennen, nicht z. B. Kabelziehen.

    – Benutzer207421

    6. März 2020 um 7:43 Uhr

Benutzeravatar von chandank
Chandank

get sock opt kann etwas nützlich sein, aber eine andere Möglichkeit wäre, einen Signal-Handler für SIGPIPE zu installieren. Grundsätzlich sendet der Kernel immer dann, wenn die Socket-Verbindung unterbrochen wird, ein SIGPIPE-Signal an den Prozess, und dann können Sie das Notwendige tun. Dies bietet jedoch noch nicht die Lösung, um den Status der Verbindung zu kennen. hoffe das hilft.

1391400cookie-checkWie finde ich den Socket-Verbindungsstatus in C?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy