TCP erfordert im Allgemeinen, dass Sie den Empfänger und den Absender auf Anwendungsebene synchronisieren. Kombinationen von SO_SNDBUF
tweaking oder TCP_NODELAY
alleine lösen das Problem wahrscheinlich nicht vollständig. Dies liegt daran, dass die Menge der Daten, die "im Flug" sein können, bevor send()
blockiert, mehr oder weniger gleich der Summe von:
CWIN
) und empfange Fenstergrößen ( RWIN
). Der TCP-Sender stimmt die Größe des Staufensters kontinuierlich auf die Netzwerkbedingungen ab, während TCP-Übergänge zwischen den Modi "langsamer Start", "Stauvermeidung", "schnelle Wiederherstellung" und "schnelle Neuübertragung" erfolgen. Und, ACK
gesendet hat, die die Anwendung aber noch nicht gesehen hat. Um es anders auszudrücken, nachdem der Empfänger das Lesen von Daten aus dem Socket beendet hat, blockiert send()
nur, wenn:
ACK
ing, ACK
ed-Daten bis zum Grenzwert für das Stau- oder Empfangsfenster und Das Ziel der in TCP verwendeten Algorithmen besteht darin, den Effekt eines fließenden Bytestroms statt einer Sequenz von Paketen zu erzeugen. Im Allgemeinen wird versucht, die Tatsache, dass die Übertragung in Pakete quantisiert wird, so gut wie möglich zu verbergen, und die meisten Socket-APIs spiegeln das wider. Ein Grund dafür ist, dass Sockets möglicherweise nicht auf der obersten TCP- (oder gar IP-) Ebene implementiert werden: Betrachten Sie einen Unix-Domain-Socket, der dieselbe API verwendet.
Es ist im Allgemeinen nicht ratsam, sich auf TCP-zugrunde liegende Implementierungsdetails für das Anwendungsverhalten zu verlassen. Bleiben Sie beim Synchronisieren auf der Anwendungsebene.
Wenn die Latenz in der Situation, in der Sie die Synchronisation durchführen, ein Problem darstellt, sollten Sie auch etwas über Interaktionen zwischen Nagle's lesen Algorithmus und verzögert ACK
, die unter bestimmten Umständen unnötige Verzögerungen einführen können.
Ich hatte vor ein paar Wochen auch das gleiche Problem, als ich einen VoIP-Server implementierte. Nach einigen Tagen konnte ich mir eine Lösung einfallen lassen. Wie viele andere bereits erwähnten, gibt es keinen direkten Systemaufruf, um die Aufgabe zu erledigen. Stattdessen
ACK
-Option TCP_INFO
erhalten haben. ACK
nicht erhalten haben, warten Sie einige Millisekunden und überprüfen Sie es erneut. Dies kann fortgesetzt werden, bis eine Auszeit erreicht ist. Sie müssen es als Wrapper-Funktion für den Aufruf von send () implementieren.
Sie benötigen tcp_info
struct von <netinet/tcp.h>
. Es ist die Datenstruktur für Informationen über Ihre TCP-Verbindung .
Hier ist der Pseudocode
%Vor% Hier enthält tcpi_unacked
member die Anzahl der Pakete unbestätigt Ihrer Verbindung. Wenn Sie es kurz nach dem send () - Aufruf lesen, enthält es die Anzahl der unpacked Pakete, die der Anzahl der gesendeten Pakete entspricht. Mit der Zeit wird die Anzahl der ungeschachtelten Pakete auf Null verringert. Daher müssen Sie den Wert von tcpi_unacked
regelmäßig überprüfen, bis er Null erreicht. Wenn die Verbindung halb geöffnet ist, erhalten Sie niemals ACK
s, während Sie eine Endlosschleife verursachen. Für solche Szenarien müssen Sie möglicherweise einen timeout -Mechanismus wie oben implementiert hinzufügen.
Auch wenn diese Frage schon lange gestellt wurde, kann diese Antwort jemandem helfen, der das gleiche Problem hatte. Ich muss erwähnen, dass es genauere Lösungen für dieses Problem geben könnte als diese Lösung. Da ich ein Neuling für Systemprogrammierung und C / C ++ bin, könnte ich mir das vorstellen.
Warum nicht einfach einen blockierenden Sockel verwenden?
Das mag etwas veraltet sein, aber hier ist eine Erklärung zu blockierenden / nicht-blockierenden und überlappenden IO.
Es würde helfen, wenn wir wüssten, welche Sprache und Betriebssystem Sie verwenden, BTW, um besser Code-Snippets zu zeigen.
Wenn Sie % co_de verwenden % , um setsockopt()
auf einen Wert, der groß genug ist, um ein Paket zu senden, dann sollte der nächste SO_SNDBUF
auf diesem Socket blockieren, bis das vorherige Paket bestätigt wird. Jedoch, nach send()
, die Socket-Puffergröße muss vor tcp(7)
/ listen()
gesetzt werden.
Der Hauptpunkt bei der Verwendung von TCP ist das Ausblenden dieses einzelnen ACK aus Anwendungen. Wenn Sie jeden ACK erkennen müssen, implementieren Sie Ihr eigenes Protokoll mit UDP oder IP. TCP ist wahrscheinlich ein Overkill. Oder Sie können den Stapel nach oben gehen und ein Protokoll wie HTTP als Transport verwenden.
Tags und Links c++ sockets linux network-programming