2017-01-24 3 views
1

Ich mache einen Test mit TCP-Client-Anwendung in einem Raspberry Pi (Server im PC), mit PPP (Point-to-Point-Protokoll) mit einem LTE-Modem. Ich habe C-Programm mit Sockets verwendet und die Antwort des Systemaufrufs überprüft. Ich wollte testen, wie Socket in einem schlechten Abdeckungsbereich funktioniert, also habe ich ein paar Tests gemacht, um die Antenne zu entfernen.TCP Sockets in C mit schlechtem Netzwerk

Ich habe die nächsten Schritte folgen:

  1. eine Verbindung zum Server -> OK
  2. starten Daten (Schreibsystemaufruf) zu senden -> OK (I auch in dem Server überprüfen)
  3. ich entfernte die Antenne des LTE-Modem (kein Netzwerk ist, kann es nicht ping)
  4. Weiter Senden von Daten (schreiben Systemaufruf) ->OK (Server nicht empfängt anyth ing !!!)
  5. Es beendet Daten und geschlossene Buchse zu senden ->OK (Verbindung noch geöffnet ist, und es gibt keine Daten, da die Antenne entfernt wurde)
  6. Programm beendet wurde
  7. ich wieder die Antenne
  8. setzen

Einige Zeit später wurden die Daten hochgeladen und die Verbindung geschlossen. Aber ich habe einen anderen Test nach diesen Schritten, aber mit mehr Daten, und es hat diese Daten nicht hochgeladen ...

Ich weiß nicht, ob es eine Möglichkeit, um sicherzustellen, dass die auf TCP-Server geschriebene Daten vom Server empfangen werden (Ich dachte, dass TCP-Schicht dies gewährleistet ..). Ich könnte es manuell mit einem ACK tun, aber ich denke, dass es ein besserer Weg sein muss.

Senden Teilenummer:

while(i<100) 
    { 
     sprintf(buf, "Message %d\n", i); 
     Return = write(Sock_Fd, buf, strlen(buf)); 
     if(Return!=strlen(buf)) 
     { 
      printf("Error sending data to TCP server. \n"); 
      printf("Error str: %s \n", strerror(errno)); 
     } 
     else 
     { 
      printf("write successful %d\n", i); 
      i++; 
     } 
     sleep(2); 
    } 

Vielen Dank für Ihre Hilfe.

+0

Sind Sie nicht-blockierende Sockets verwenden? Wie schreiben Sie die Daten und überprüfen die Ergebnisse? Können Sie bitte versuchen, ein [minimales, vollständiges und verifizierbares Beispiel] (http://stackoverflow.com/help/mcve) des Client-Programms zu erstellen und uns zu zeigen? –

+0

Ich benutze den Standardmodus, Blockiermodus Ich denke (wenn ich eine Verbindung zum Server herstelle, wartet es, bis die Verbindung hergestellt wurde). –

Antwort

4

Die write() -syscall gibt true zurück, da der Kernel die Daten puffert und in die Out-Queue des Sockets stellt. Es wird aus dieser Warteschlange entfernt, wenn die Daten und vom Peer gesendet wurden. Wenn die OutQueue voll ist, wird der write -syscall blockiert.

Um festzustellen, ob die Daten vom Peer nicht bearbeitet wurden, müssen Sie die Größe der Outqueue überprüfen.Mit Linux können Sie ein ioctl() für diesen Einsatz:

ioctl(fd, SIOCOUTQ, &outqlen); 

Allerdings wäre es mehr sauber und tragbar sein, eine Inband-Methode verwenden, um zu bestimmen, ob die Daten empfangen wurden.

+0

Was ist eine "Inband-Methode"? Ich habe bei google nachgeschaut, aber ich habe keine eindeutige Erklärung gefunden –

+2

@JulenUranga Das bedeutet, dass die Quittung über die tcp-Verbindung selbst gesendet wird. Client: "DO STH" - Server: "FERTIG". – Ctx

1

TCP/IP ist eher primitive Technologie. Internet mag neu klingen, aber das ist wirklich antikes Zeug. TCP wird benötigt, weil IP fast keine Garantien bietet, aber TCP fügt nicht wirklich viele Garantien hinzu. Seine Hauptfunktion besteht darin, ein Paketprotokoll in ein Stream-Protokoll umzuwandeln. Das heißt TCP garantiert eine Byte-Reihenfolge; Keine Bytes werden außerhalb der Reihenfolge ankommen. Zählen Sie nicht auf mehr als das.

Sie sehen, dass Protokolle über TCP zusätzliche Prüfungen hinzufügen. Z.B. HTTP hat die bekannten HTTP-Fehlercodes, gerade weil es sich nicht auf den Fehlerstatus von TCP verlassen kann. Sie müssen wahrscheinlich dasselbe tun - oder Sie können in Betracht ziehen, Ihren Dienst als HTTP-Dienst zu implementieren. "RESTful" bezieht sich auf eine API-Designmethodik, die eng der HTTP-Philosophie folgt; Dies könnte für Sie relevant sein.

1

Die kurze Antwort auf Ihre 4. und 5. Themen wurde als Verknüpfung von this answer (lesen Sie die ganze Antwort auf mehr Informationen zu erhalten) genommen

A Buchse einen Sendepuffer hat und wenn ein Aufruf der send () Funktion ist erfolgreich, es bedeutet nicht, dass die angeforderten Daten tatsächlich tatsächlich gesendet wurden, es bedeutet nur, dass die Daten dem Sendepuffer hinzugefügt wurden. Bei UDP-Sockets werden die Daten normalerweise bald gesendet, wenn nicht sofort, aber bei TCP-Sockets kann es eine relativ lange Verzögerung zwischen dem Hinzufügen von Daten zum Sendepuffer und dem tatsächlichen Senden der Daten durch die TCP-Implementierung geben. Wenn Sie einen TCP-Socket schließen, befinden sich möglicherweise noch ausstehende Daten in dem Sendepuffer, der noch nicht gesendet worden ist, aber Ihr Code betrachtet es als gesandt, seit der Aufruf von Send() erfolgreich war. Wenn die TCP-Implementierung den Socket sofort bei Ihrer Anfrage schließt, sind all diese Daten verloren und Ihr Code würde davon nicht einmal etwas wissen. TCP wird als zuverlässiges Protokoll bezeichnet und Datenverluste sind nicht sehr zuverlässig. Aus diesem Grund wird ein Socket, der noch Daten zu senden hat, in einen Zustand mit der Bezeichnung TIME_WAIT versetzt, wenn Sie ihn schließen. In diesem Zustand wird gewartet, bis alle ausstehenden Daten erfolgreich gesendet wurden oder bis ein Timeout erreicht wird. In diesem Fall wird der Socket zwangsweise geschlossen.

Die Zeitspanne, die der Kernel wartet, bevor er den Socket schließt, unabhängig davon, ob noch ausstehende Daten gesendet werden oder nicht, wird als Verweilzeit bezeichnet.

BTW: diese Antwort bezieht sich auch auf die docs wo Sie detaillierte Informationen sehen

+0

"Wenn die TCP-Implementierung den Socket sofort bei Ihrer Anfrage geschlossen hat, wären alle diese Daten verloren". Was bedeutet das? Der Server schließt die Verbindung oder der Client schließt den Socket? Oder beides? –

+1

@JulenUranga Dies bedeutet, dass die Standardimplementierung eine Verbindung nicht sofort schließen wird: Sie würde versuchen, alle noch vorhandenen Daten im Puffer zu senden und dann zu versuchen, den Socket _gracefully_ zu schließen. Aber wenn Sie den Socket ** sofort ** schließen möchten (indem Sie beispielsweise _Linger Time_ deaktivieren), wird er geschlossen _forcefully_ bedeutet, dass alle ausstehenden Daten im Puffer ignoriert und die Verbindung sofort geschlossen wird. –

Verwandte Themen