2010-12-13 10 views
3

Ich schreibe zwei Anwendungen (in C), die mehrere Anrufe zum Senden und Empfangen (z. B. ich bin eine Remote-Datei kopieren).Gründe für einen langsamen recv Anruf

Ich sende immer einen 64 Byte Header, der die Länge des folgenden Nachrichtentexts und einige andere Informationen enthält.

Beim Testen meiner Anwendung auf einige Dateien erkannte ich, dass einige Recv-Aufrufe ziemlich lange dauern (ca. 40 ms). Mit strace habe ich herausgefunden, dass es zuerst beim Senden eines Nachrichtentextes von 377 Bytes passiert (was in diesem Fall den gesamten Inhalt meiner zu kopierenden Datei betrifft).

Die Serveranwendung beginnt mit dem Senden des Nachrichtentexts, der ungefähr 48 us dauert. Jetzt verbraucht die Clientanwendung etwa 38 ms, um diese Bytes zu empfangen.

Von diesem Zeitpunkt an verbrauchen alle empfangenen Anrufe so viel Zeit, da sie jeweils in einem Empfang blockieren und auf die Antwort warten.

Server Strace

[pid 27158] 1292236124,465827 send (6, „\ 0 \ 0 \ 1 \ 271 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0core.fwrite \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 "..., 64, 0) = 64 < 0.000031>

[pid 27158] 1292236124.466074 senden (6," \ 0 \ 0 \ 0 \ 1 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 10 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 1 \ 0 \ 0 \ 0 \ 0" ..., 377, 0) = 377 < 0,000048>

Kunden strace

[pid 27159] 1292236124.466364 recv (4, "\ 0 \ 0 \ 1 \ 271 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0core.fwrite \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 "0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0,,, 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 10 \ 0 \ 0 \ 0 \ 1 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 1 \ 0 \ 0 \ 0 \ 0 " ..., 377, 0) = 377 < 0.037456>

Dieses Problem gibt mir wirklich eine harte Zeit, da ich nicht verstehe, warum der Empfangsanruf auf dem Client so viel Zeit braucht.

Alle Hinweise würden sehr geschätzt werden.

+0

wie abwickeln sagt, es kann Nagle bei der Arbeit sein. Wenn Sie jedoch Dateien kopieren, wird der Name des Spiels nicht durchgerechnet? Ich verstehe es nicht wirklich "Von diesem Zeitpunkt an verbrauchen alle eingehenden Anrufe so viel Zeit, da sie jeweils einen Empfang blockieren und auf die Antwort warten." wartet der Server auf den Client? – lijie

Antwort

7

Klingt wie Nagle's algorithm zu mir. Sie reichen nicht genügend Daten ein, es verzögert sich also eine Weile, falls mehr kommt. Sie können es über eine Socket-Option deaktivieren und es erneut versuchen.

+2

Die Option ist 'TCP_NODELAY' und es wird in tcp (7) erklärt [http://linuxmanpages.com/man7/tcp.7.php] – salva

+0

Hinweis, für eine Dateikopie möchten Sie wahrscheinlich nicht deaktivieren, als Es ist effizienter, den TCP-Stack entscheiden zu lassen, wie die Nachrichten zu bündeln sind. – nos

0

Ja, das ist auf jeden Fall Nagles Algorithmus. Ich schlage vor, Sie lesen es weiter, denn wenn Sie große Datenmengen senden, sollte es senden, sobald es "viele" Daten hat. Ohne mich selbst zu lesen, bin ich nicht ganz sicher, wie viel "Lose" sind, aber es ist wahrscheinlich konfigurierbar.

Wenn Sie jedoch eine Datei pro Verbindung erstellen, sollten Sie kein Problem mit kleinen Dateien haben, wenn Sie den Header und den Inhalt auf einmal versenden - was Sie ohnehin tun sollten, um den Durchsatz zu verbessern. Wie Lijie (mehr oder weniger) sagt "der Durchsatz ist der Name des Spiels". Sie müssen Ihren Header zusammen mit den Dateidaten puffern. Dies ist eine der wenigen Situationen, in denen ich Multithreading empfehlen könnte - einen Thread, um den Puffer aus der Datei zu füllen, und einen weiteren, um den Socket aus dem Puffer zu laden. Sie müssen den Puffer und die zugehörigen Variablen mit einem Mutex schützen, und ich empfehle, auch eine Zustandsvariable zu verwenden.Der Dateilese-Thread signalisiert, wenn er mehr Daten hinzugefügt hat und wartet, wenn der Puffer voll ist, und der Socket-Schreib-Thread signalisiert, wenn er gelesen hat und wartet, wenn der Puffer leer ist. Der Datei-Lese-Thread sollte nach dem Schreiben des 64-Byte-Headers nicht signalisieren. Lassen Sie zuerst einen vollen Datenpuffer laden.

Sie können auch versuchen, zwei Puffer zu verwenden und sie abwechselnd zu verwenden, um Mutex-Sperrverzögerungen zu reduzieren. Wenn Sie es richtig machen, schreibt der Datei-Lese-Thread in den Puffer A, während der Socket-Schreib-Thread den Puffer B liest und umgekehrt und die Threads warten seltener auf einen Mutex.

Selbst mit einer solchen Strategie könnte es sich trotzdem lohnen, Nagles Algorithmus zu deaktivieren. Abgesehen von allem, wenn Ihr Code so konzipiert ist, dass viele kleine Pakete sowieso vermieden werden, ist Nagles Algorithmus überflüssig.

+0

stellte sich heraus, dass Nagles Algorithmus tatsächlich das Problem war. Danke für Ihre Hilfe. – herzrasen