hi
Ich habe eine Frage bezüglich der HTTP / TCP Übertragung an sich...
normalerweise geht soweit ich das verstanden hab HTTP mit TCP so:
-> SYN
<- SYN/ACK
-> ACK
-> GET bild.gif
<- HTTP header + erste Daten
-> ACK
<- FIN + restliche Daten
-> ACK
-> FIN
<- ACK
nach jedem datenpaket kommt ein ACK
der lwIP ( 1.4.0) macht hier aber soetwas:
-> SYN
<- SYN/ACK
-> ACK
-> GET bild.gif
<- HTTP header
<- rest HTTP header + erste daten
-> ACK (hier werden die 2 pakete zusammen in der seq/ack nummer gezählt)
<- FIN + restliche daten
-> ACK
-> FIN
<- ACK
ich dachte erst "sliding window"
aber hier werden die pakete "nur" später geACKed
hier werden aber mehrere Pakete zusammen geACKed
mir gehts darum wie man dieses "feature" nennt
desweiteren kann es sein das der client zwischen HTTP header und dem
rest header auch mal ein ACK sendet .. auch wenn es in das window passt.
hier kracht es dann irgendwie ...
bzw hier kommt dann eine retransmission
Nach jedem Datenpaket ein ACK zu senden ist recht ineffizient, das läuft
auf ein Ping-Pong-Protokoll heraus. Normal ist das für TCP nicht; TCP
wurde erfunden um besser zu sein. Gut, wenn ich auf einem 8bitter
unbedingt TCP implementieren müsste, um mit einem Browser zu reden,
würde ich das auch auf ein Ping-Pong-Protokoll herunterhandeln.
Ein eigenes ACK-Paket wird normalerweise nur gesendet, wenn die
Datenübertragung offenbar nur in eine Richtung erfolgt, sonst steckt die
ACK-Information einfach mit im TCP-Header der Gegenrichtung; der Platz
dafür ist sowieso reserviert.
Außerdem bezieht sich ACK genaugenommen nicht auf Pakete, sondern auf
die transportierten Bytes; mehrere Pakete mit einem ACK zu bestätigen
ist also normal. Theoretisch wäre es sogar zulässig, nur ein halbes
Paket zu ACKen; der Absender kann dann das ganze Paket wiederholen oder
nur die hintere Hälfte, oder die hintere Hälfte + folgende Daten.
Das ACK für das GET steckt z.B. in demselben Paket wie der HTTP-Header,
weil der Server sowieso Daten zum Client schicken muß, da kann er das
ACK gleich mitschicken. Wenn der Server sich mit dem nächsten Paket dann
zu viel Zeit läßt, schickt der Client schonmal ein ACK, damit der Server
weiß, daß sein erstes Paket (das mit dem HTTP-Header) angekommen ist und
er das nicht wiederholen muß. Wenn der Server seine Pakete schneller
hintereinander schickt, gibt's eben nur ein gemeinsames ACK für beide.
Einen besonderen Namen gibt es für diese Situation aber nicht.
Die "Window size" spielt dabei auch noch eine Rolle. Die steht auch in
jedem TCP-Paket drin, und gibt an, wieviel die Gegenseite noch über das
letzte ACK hinaus senden darf, also praktisch wieviel Platz der
Empfänger noch in seinem Puffer hat. Je nachdem, wie schnell der
Empfänger die Daten verarbeitet hat, kann das sehr klein werden, und der
Absender (in diesem Fall wohl der Server) muß dann für jedes Paket
einzeln auf ein ACK warten.
ich habe den fehler eingrenzen können ...
aktuell habe ich einen fehler im MSS und windowsize
ich muss das mit dem sliding window nochmal genau durchlesen
ein einzelnes ACK nach einer contiguous übertragung von mehreren
segemnten ist erlaubt
einzig das SACK sollte ich glabe ich für den kleinen stack weglassen
da ich sonst nur schwer die möglichkeit habe einzelne segmente
zwischenzupuffern und die ACKs durchzuzählen
was ch aktuell nicht beachte ist der window wert des ACK vom client
nach 6 dateien mit 4 contiguous segmenten geht dem der puffer aus
das ACK sendet er weil nur noch 500 byte window frei waren
ich hab aber fröhlich 1460 bytes reingepackt
deswegen fiel mir das bei einzelnen dateien nicht auf
werde das morgen so umbauen das ich die windowsize einbeziehe und an die
applikation weiterreiche mit der maximal möglichen anzahl an byts die
ich senden kann
dann sollte das gehen ...
Normalerweise kann der Applikation des Senders die Windowsize des
Empfängers egal sein, weil der TCP-Sendepuffer dazwischen vermittelt.
Die Applikation gibt höchstens so viele Daten an TCP wie eben noch in
den Sendepuffer passen, TCP sendet die Daten aus dem Puffer, soweit es
Flußkontrolle (Windowsize des Empfängers) und congestion control
erlauben, und wenn ein ACK kommt, wird entsprechend wieder Platz im
Sendepuffer frei.
Auf kleinen Prozessoren, wo kein Platz für den Sendepuffer ist, sieht
das natürlich anders aus; da muß TCP für jedes Paket, das es senden
will, die Applikation nach den entsprechenden Daten fragen.
Nosnibor schrieb:> . Normal ist das für TCP nicht; TCP> wurde erfunden um besser zu sein. Gut, wenn ich auf einem 8bitter> unbedingt TCP implementieren müsste, um mit einem Browser zu reden,> würde ich das auch auf ein Ping-Pong-Protokoll herunterhandeln.
Und dabei auf die Schnau... fallen. Moderne Betriebssysteme machen das
nicht mehr mit.
Nosnibor schrieb:> Auf kleinen Prozessoren, wo kein Platz für den Sendepuffer ist, sieht> das natürlich anders aus; da muß TCP für jedes Paket, das es senden> will, die Applikation nach den entsprechenden Daten fragen.
ja
genau das versuche ich zu umgehen
bisher habe ich ja bei eingehenden ACKs
die ack/seq nummer geprüft und kann so feststellen ob die gegenseite
alles richtig empfangen hat
das macht das system zwar einfach aber auch langsam ..
ich habe deswegen eine segmentliste für jede übertragung wo ich mir die
reihenfolge , acknummer , seqnummer und flags sowie segmentsize merke
so kann ich theoretisch jedes segment durch die applikation
wiederherstellen
wenn es korrekt geacked wurde lösche ich es aus der liste
wenn ich 2 segmente sende (contiguous ) dann erstelle ich nur 1 segment
mit eben passender größe
ich habe heute etwas experimentiert ..
dabei habe ich zB festgestellt das manche browser bei windowsize
1000bytes schreiben ..
aber in den options steht ein multiplikator .. den ich bisher vergessen
hatte
ich habe diverse wireshark caps wo 5-8 segemnte gesendet werden und dann
erst ein ACK erfolgt
warum er aber so viel zeit hat 5-8 pakete zu senden hab ich nch nicht
kappiert
bei mir sendet er nach 2 paketen ein ACK
ich sende eine MSS von 1460 und Window von 2*1460
liegt evtl auch daran
Jim Meba schrieb:> Nosnibor schrieb:>> . Normal ist das für TCP nicht; TCP>> wurde erfunden um besser zu sein. Gut, wenn ich auf einem 8bitter>> unbedingt TCP implementieren müsste, um mit einem Browser zu reden,>> würde ich das auch auf ein Ping-Pong-Protokoll herunterhandeln.>> Und dabei auf die Schnau... fallen. Moderne Betriebssysteme machen das> nicht mehr mit.
Wenn es nicht auf Durchsatz ankommt, sollte das immer gehen. Als
Empfänger kann ich jederzeit über die windowsize regeln, wann der Sender
senden darf, und als Sender kann ich einfach aufs ACK warten, bevor ich
das nächste Paket sende. Das wird dann allerdings langsam, weil der
Empfänger eine Weile (200ms war mal standard) zögert, bevor er ein
"leeres" ACK schickt.
ützgür schrieb:> dabei habe ich zB festgestellt das manche browser bei windowsize> 1000bytes schreiben ..> aber in den options steht ein multiplikator .. den ich bisher vergessen> hatte
Das sollte einfach abzustellen gehen: beim three-way-handshake die
entsprechende Option nicht senden, dann weiß die Gegenseite, daß du kein
window scaling kannst und sendet die echte windowsize ohne
Multiplikator. Der Nachteil (max. 64kb Window) dürfte auf einem kleinen
embedded System kaum ins Gewicht fallen, weil nicht so viele Daten zu
senden sind.
>> ich habe diverse wireshark caps wo 5-8 segemnte gesendet werden und dann> erst ein ACK erfolgt> warum er aber so viel zeit hat 5-8 pakete zu senden hab ich nch nicht> kappiert>> bei mir sendet er nach 2 paketen ein ACK
Der Empfänger wird natürlich in jedem Paket, das er selber sendet, die
aktuelle Ack-Nummer mitschicken. Wenn er selber keine Daten zu senden
hat, muß er dazu leere Pakete schicken. Eine feste Vorschrift, wann er
das machen soll, gibt es nicht, soweit ich weiß. Es war mal üblich, das
nach 200ms zu tun, aber es gibt bestimmt Gründe (z.B. bessere
Unterstützung des slow-start-Algorithmus) für komplizierteres Verhalten.
Da würde ich mir einfach keinen Kopf drum machen, wann der Empfänger
seine ACKs schickt, solange er es überhaupt tut. Und wenn, dann muß man
sich auch die Zeitstempel der Pakete genau ansehen. Und nicht vergessen,
wo der Wireshark sitzt: manchmal begegnen sich Pakete auf der "Leitung"
(incl. Netzwerkadapter und Ethernet-Treiber), und im Wireshark sieht
immer der eigene Netzwerkstack besser und vernünftiger aus als die
Gegenseite.
Bei Windows Vista, 7 und 8 ist der Timeout 200ms.
Bei Windows XP konnte man ihn in der Registry konfigurieren.
Bei Linux ist der Timeout viel kürzer.
Windows Programme können die Option TCP_NODELAY Setzen, um den Timeout
ganz abzuschalten. Dann wird jedes empfangene Paket sofort quittiert.
Telnet mahct das z.B. sinnigerweise.
Leider gibt es keine Möglichkeit, dass der Server dem Client mitteilt,
er soll bitte jedes Paket sofort quittieren.
> Es war mal üblich, das nach 200ms zu tun
Ursprünglich war es vorgesehen, dass der Empfänger jedes Paket einzeln
möglichst rasch quittiert. Dann kam der Nagle Algorithmus (RFC 896 und
RFC 1122) hinzu. Das danach neue Verhalten ist nicht mehr 100%
kompatibel zum alten. Und deswegen gucken die Micro-Webserver (die nur
kleine Window-Sizes unterstützen) jetzt in die Röhre.
Ich fände es gut, wenn die Web-Browser an dieser Stelle lernen würden.
Spätestens nach ein paar Paketen müsste der Browser merken, dass der
Server offensichtlich IMMER ein ACK für jedes Paket (oder für jedes n-te
Paket) erwartet. Darauf kann er sich einstellen, indem er beim nächsten
Verbindungsaufbau die Option TCP_NODELAY setzt.
Bei Curl kann man das übrigens netterweise per Kommandozeilenparameter
steuern.
Vor einigen Jahren gab es mal einen Workaround der bei Windows Clients
half, leider klappt er nicht mehr. Damals war Windows noch so gestrickt,
dass es nur volle Pakete (size=MSS) verzögert beantwortete. Nach dem
Motto " da kommt sicher noch mehr". Aber halbvolle Pakete hatte Windows
immer sofort beantwortet. Es gab dazu mal eine Patch für µIP, aber wie
gesagt wurde der zurück gezogen.
hi
vielen dank für die antworten ...
ich bekomme einfach nicht mehr als 2 pakete raus ...
ohne das ein ACK folgt
demnach kann man das zwar so laufe lassen ..
das ist aber enormer aufwand für die verwaltung
ebenso schwerfällig wenn doch mal ein zwischenACK kommt
den fall bekomm ich nur schwer weggefiltert
das mit der datenlänge ist auch so ein ding was ich schonmal gelesen
habe.
aber das scheint wirklich nur experimentell gewesen zu sein.
der µIP hatte mal einen patch das er ein 2tes ACK sendet zwar leer ..
aber eben kurz nach dem datepaket um dem client zum anfragen zu zwingen
aber neuere browser verhalten sich da auch anders ...
ich versuche mal noch diverse dinge ...
habe bisher auch immer versuch caps von verschiedenen verbindungen
anzuschauen und zu verstehen
aufgrund der zigtausend RFCs blickt da glaube keiner mehr 100%ig durch
ützgür schrieb:> ich bekomme einfach nicht mehr als 2 pakete raus ...> ohne das ein ACK folgt>> demnach kann man das zwar so laufe lassen ..> das ist aber enormer aufwand für die verwaltung> ebenso schwerfällig wenn doch mal ein zwischenACK kommt> den fall bekomm ich nur schwer weggefiltert
Das verwirrt mich jetzt langsam. Wo ist das Problem für den Sender, wenn
mehr ACKs zurückkommen als erwartet?
Wenn du partout nicht damit klarkommst, im unerwarteten Moment auf ein
ACK reagieren zu müssen, dann schiebe das doch einfach auf: Wenn ein ACK
reinkommt, einfach die nötige Information irgendwo speichern, und später
dann entsprechend reagieren. Viel Information ist das ja nicht:
- ein Flag, daß mindestens ein ACK empfangen wurde
- die "größte" geACKte Sequenznummer
- das aktuelle Ende (Sequenznummer) vom receive window
Wenn in der Zwischenzeit mehrere ACKs kommen, muß man die Information
nur updaten, aber mehr wird es davon nicht.
> aufgrund der zigtausend RFCs blickt da glaube keiner mehr 100%ig durch
In der aktuellen rfc-index.txt steht zu jedem RFC die Gültigkeit. Alles
was nicht aufm "standards track" ist, ist eh nur Unterhaltungsliteratur,
und zu jedem Standard-RFC steht da, durch welche es ergänzt oder ersetzt
wurde. Alles was ausdrücklich optional ist, braucht man nicht
implementieren, ebenso alles, wo nicht MUST oder SHOULD (gemäß RFC2119,
IIRC) dabeisteht. Und wenn man dabei keine Fehler macht, ist man immer
noch standardkonform, also wo ist das Problem? :)
Im Ernst: eine verständliche und vollständige TCP-Beschreibung habe ich
auch noch nie gesehen. Viel pessimistische Kreativität ("was könnte noch
alles schiefgehen?") ist nötig, wenn man sein eigenes TCP bauen will,
sonst macht man damit im Betrieb viele "interessante" Erfahrungen.