Hi, für eine Anwendung nutze ich einen TCP Server. Dieser läuft auf
einem Linux Rechner und wurde in python implementiert.
Sobald Nachrichten empfangen werden soll nur ein ACK Message
zurückgesendet werden. Mir gelingt bisher nur das versenden von den
empfangen Daten.
Es gibt die Funktion sendto, allerdings ist es mir nicht gelungen ein
ACK Nachricht an den Client zu senden.
>> Die Variable cnt bekommt an keiner Stelle einen Wert zugewiesen. Du> meintest vielleicht str(data)?
Korrekt. Ich bezweifle auch, daß "SERVER_PORT = XXXX" den gewünschten
Effekt hat.
JoMil schrieb:> allerdings ist es mir nicht gelungen ein ACK Nachricht an den Client zu> senden.
Wenn man alle genannten Fehler raus macht, funktioniert es doch?
JoMil schrieb:> TCP Server
beißt sich in deiner Implementierung mit
JoMil schrieb:> Nachrichten
--> TCP ist ein Stream. Du kriegst die Bytes in der richtigen
Reihenfolge. Aber: es ist nicht gesagt, dass jedes "read" exakt einem
"write" an der Gegenstelle entspricht. Das Packet könnte fragmentiert
worden sein, dann kriegst du die Daten evtl. auf mehrere reads verteilt,
oder es könnten mehrere writes zusammengefasst worden sein (NAGLE am
Server), dann kommen in einem read mehrere "Nachrichten" auf einmal.
Das muss dein Code abhandeln können.
Fieserweise funktioniert sowas beim Testen immer ganz toll, wenn Sender
und Empfänger "localhost" sind.
Einfache Option wäre, auf mqtt oder http statt plain TCP zu setzen. Ist
in python ja genauso fix eingebaut.
Εrnst B. schrieb:> --> TCP ist ein Stream. Du kriegst die Bytes in der richtigen> Reihenfolge. Aber: es ist nicht gesagt, dass jedes "read" exakt einem> "write" an der Gegenstelle entspricht. Das Packet könnte fragmentiert> worden sein, dann kriegst du die Daten evtl. auf mehrere reads verteilt,> oder es könnten mehrere writes zusammengefasst worden sein (NAGLE am> Server), dann kommen in einem read mehrere "Nachrichten" auf einmal.
Bitte informiere Dich, was ein Betriebssystemkernel mit empfangenen
TCP-Fragmenten macht, bevor er sie an den Userspace weitergibt. Und
bitte gib niemandem mehr einen "Rat" in diesen Dingen, bevor Du es nicht
absolut sicher weißt. Vielen Dank.
Ein T. schrieb:> Bitte informiere Dich, was ein Betriebssystemkernel mit empfangenen> TCP-Fragmenten macht, bevor er sie an den Userspace weitergibt.
Oh. Jetzt wird's spannend. Welche magische Veränderung, die meinen
Aussagen oben widerspricht, sollte der Kernel denn deiner Meinung nach
am TCP-Datenstrom vornehmen?
Εrnst B. schrieb:> Ein T. schrieb:>> Bitte informiere Dich, was ein Betriebssystemkernel mit empfangenen>> TCP-Fragmenten macht, bevor er sie an den Userspace weitergibt.>> Oh. Jetzt wird's spannend. Welche magische Veränderung, die meinen> Aussagen oben widerspricht, sollte der Kernel denn deiner Meinung nach> am TCP-Datenstrom vornehmen?
Hast Du Dich informiert? Wenn ja: zu welchen Erkenntnissen bist Du dabei
gelangt?
Εrnst B. hat recht. Wenn ich "Hallo" und "Welt" sende, ist das aus TCP
sicht das selbe, wie "HalloWelt" zu senden. Es gibt eine Sequenznummer,
die funktioniert wie ein byte offset in einen ring buffer. Und die Ack
Nummer, die sagt, bis hier hab ich alles gekriegt. Eine Info, wo ein
Paket anfängt und endet, gibt es in den Daten nicht. Die Grösse der IP
Pakete, in denen die Daten übertragen werden, ist begrenzt. Und es gibt
eine window size, die auch noch limitiert, wie viel auf einmal gesendet
werden darf, für congestion control. Die Daten können also beliebig in
TCP Pakete verteilt werden. Das ist nicht wie ein IP Paket, das
aufgespalten & wieder zusammengesetzt wird.
Guten Morgen Ernst B.,
du hast am 28.06.2022 16:27 einen Beitrag gepostet.
Was meinst du das muss der Code abhändeln können?
Meinst du auf Client oder Server Seite?
Εrnst B. schrieb:> Ein T. schrieb:>> Wenn ja: zu welchen Erkenntnissen bist Du dabei>> gelangt?>> Dass du keine Ahnung hast.
Erfreulicherweise habe ich die und weiß daher, wie IP-Fragmentierung
funktioniert und in welcher Softwarekomponente sie stattfindet. Genau
das sehe ich bei Dir leider nicht, daher: bitte informiere Dich, bevor
Du anderen etwas Falsches erzählst. Viel Glück!
DPA schrieb:> Εrnst B. hat recht. Wenn ich "Hallo" und "Welt" sende, ist das aus TCP> sicht das selbe, wie "HalloWelt" zu senden. Es gibt eine Sequenznummer,> die funktioniert wie ein byte offset in einen ring buffer. Und die Ack> Nummer, die sagt, bis hier hab ich alles gekriegt. Eine Info, wo ein> Paket anfängt und endet, gibt es in den Daten nicht. Die Grösse der IP> Pakete, in denen die Daten übertragen werden, ist begrenzt. Und es gibt> eine window size, die auch noch limitiert, wie viel auf einmal gesendet> werden darf, für congestion control. Die Daten können also beliebig in> TCP Pakete verteilt werden. Das ist nicht wie ein IP Paket, das> aufgespalten & wieder zusammengesetzt wird.
Das ist korrekt, hat aber nichts mit dem Userspace-Prozeß zu tun, sie
"Ernst B." in seinem Beitrag
Beitrag "Re: python TCP Server" behauptet. Von der
Fragmentierung und Defragmentierung bekommt der Userspace-Prozeß nämlich
gar nichts mit und das hat auch nichts mit der Anzahl read()-Aufrufe zu
tun.
Ein T. schrieb:> Erfreulicherweise habe ich die und weiß daher, wie IP-Fragmentierung> funktioniert und in welcher Softwarekomponente sie stattfindet. Genau> das sehe ich bei Dir leider nicht, daher: bitte informiere Dich, bevor> Du anderen etwas Falsches erzählst. Viel Glück!
Wenn du deinen Kopf kräftig genug auf die Tischkante schlägst, merkst du
eventuell noch, dass IP an dieser Stelle völlig irrelevant ist.
Jemand schrieb:> Wenn du deinen Kopf kräftig genug auf die Tischkante schlägst, merkst du> eventuell noch, dass IP an dieser Stelle völlig irrelevant ist.
So lautet nun einmal der Fachausdruck, kleiner Grashüpfer. Die Aussage
"Das Packet könnte fragmentiert worden sein, dann kriegst du die Daten
evtl. auf mehrere reads verteilt," bezieht sich auf genau diesen
Fachausdruck. Vielleicht solltest Du Deinen Kopf nicht immer so schlecht
behandeln.
Ein T. schrieb:> Jemand schrieb:>> Wenn du deinen Kopf kräftig genug auf die Tischkante schlägst, merkst du>> eventuell noch, dass IP an dieser Stelle völlig irrelevant ist.>> So lautet nun einmal der Fachausdruck, kleiner Grashüpfer. Die Aussage> "Das Packet könnte fragmentiert worden sein, dann kriegst du die Daten> evtl. auf mehrere reads verteilt," bezieht sich auf genau diesen> Fachausdruck. Vielleicht solltest Du Deinen Kopf nicht immer so schlecht> behandeln.
Mitnichten, das ist bloß das, was du krampfhaft verstehen willst. Ich
hoffe doch, dass du nicht gleich anfängst von Dateisystemen oder der
Post zu reden, denn dort gibt es diese Fachbegriffe ebenso, und mit IP
haben die dort nichts zu tun.
Ein T. schrieb:> Das ist korrekt, hat aber nichts mit dem Userspace-Prozeß zu tun, sie> "Ernst B." in seinem Beitrag> Beitrag "Re: python TCP Server" behauptet. Von der> Fragmentierung und Defragmentierung bekommt der Userspace-Prozeß nämlich> gar nichts mit und das hat auch nichts mit der Anzahl read()-Aufrufe zu> tun.
DIe Aussage von Εrnst B war:
Εrnst B. schrieb:> --> TCP ist ein Stream. Du kriegst die Bytes in der richtigen> Reihenfolge. Aber: es ist nicht gesagt, dass jedes "read" exakt einem> "write" an der Gegenstelle entspricht.
Und da hat er absolut recht damit. Und wie TCP funktioniert, ist hier
keineswegs irrelevant. Bei TCP werden die Daten beliebig auf TCP Pakete
verteilt. Diese enthalten keine Information darüber, welcher Teil des
Datenstroms zu welchem Write der Gegenstelle gehört. Ergo kann die
Gegenstelle das nicht wissen. Ergo kann sie nicht sicher stellen, das es
ein Read für jedes Write gibt. So einfach ist das.
Ein T. schrieb:> Jemand schrieb:>> Wenn du deinen Kopf kräftig genug auf die Tischkante schlägst, merkst du>> eventuell noch, dass IP an dieser Stelle völlig irrelevant ist.>> So lautet nun einmal der Fachausdruck, kleiner Grashüpfer. Die Aussage> "Das Packet könnte fragmentiert worden sein, dann kriegst du die Daten> evtl. auf mehrere reads verteilt," bezieht sich auf genau diesen> Fachausdruck. Vielleicht solltest Du Deinen Kopf nicht immer so schlecht> behandeln.
Naja, der Ausdruck "fragmentiert" war in dem Zusammenhang eventuell
unglücklich gewählt. Es gibt IP Fragmente, aber es gibt keine TCP
Fragmente. IP und die IP Fragmente sind hier in der Tat irrelevant. Es
werden nicht immer alle Daten eines write() Aufrufes ins selbe TCP Paket
gepackt. Und es sind nicht die Pakete, die von TCP Durchnummeriert sind,
sondern die Daten. Und die HOPs zwischen den 2 Geräten mit der TCP
Verbindung könnten die Daten auch nochmal neu verteilen.
Das mit ein read pro write funktioniert höschstens solange man kleine
writes macht, und genug zeit vergeht, das dass gesendet, empfangen und
verarbeitet wird, bevor wieder was gesendet wird, und auch nichts
dazwischen was ändert. Also reine Glückssache.
JoMil schrieb:> Was meinst du das muss der Code abhändeln können?> Meinst du auf Client oder Server Seite?
Wenn der Sender ein
write("Hallo");
write("Welt");
macht, kann es sein, dass der Client einmal ein
read mit "Hallo" und einmal ein read mit "Welt" zurückbekommt.
Beim Loopback-Interface ist das recht wahrscheinlich.
Es kann aber auch sein, dass dort nur ein read zurückkommt, mit
"HalloWelt". (*)
Es kommt aber nie "WeltHallo" zurück, auch wenn das hier so ein Typ zu
glauben scheint.
Es könnte auch sein, dass der Empfänger drei reads mit "Hall","oWe","lt"
bekommt (bei größeren Datenblöcken, bei den paar Demo-Bytes eher nicht)
Kurz: TCP garantiert dir, dass deine Bytes in der richtigen Reihenfolge
ankommen, aber weder der Kernel, noch Python, noch irgendeine RFC
garantieren dir, dass jedem "write" beim Sender exakt ein "read" beim
Empfänger entspricht.
Kann ja auch nicht sein, der Sender dürfte völlig legal ein Write mit
8192 bytes machen, und der Empfänger das in einer Schleife mit Reads a
1024 bytes einlesen.
*)[[ Exkurs: mit setsockopt TCP_NODELAY wird das unwahrscheinlicher. Ist
aber kein Fix, sondern ein Verringern der Symptome ]]
Daniel A. schrieb:> DIe Aussage von Εrnst B war:>> Εrnst B. schrieb:>> --> TCP ist ein Stream. Du kriegst die Bytes in der richtigen>> Reihenfolge. Aber: es ist nicht gesagt, dass jedes "read" exakt einem>> "write" an der Gegenstelle entspricht.>> Und da hat er absolut recht damit.
Bis zu diesem Punkt hat das auch niemand bezweifelt.
> Naja, der Ausdruck "fragmentiert" war in dem Zusammenhang eventuell> unglücklich gewählt.
Genau dies ist der Punkt.
> Es gibt IP Fragmente, aber es gibt keine TCP Fragmente.
Da TCP auf IP aufbaut, können natürlich auch TCP-Daten fragmentiert
werden. Aber darum kümmert sich sowohl auf Sender- als auch auf
Empfängerseite der IP-Stack (mithin: der Kernel) der beteiligten
Betriebssysteme. Mit der Anzahl von read(2) und write(2)-Aufrufe in den
beteiligten Userspace-Programmen hat die IP-Fragmentierung aber nichts
zu tun, und deswegen hat dieser Fachausdruck auch nichts in Erklärungen
zu diesem Thema zu suchen -- insbesondere dann nicht, wenn sich die
Erklärungen an einen offensichtlichen Anfänger richten.
Εrnst B. schrieb:> Es kommt aber nie "WeltHallo" zurück, auch wenn das hier so ein Typ zu> glauben scheint.
Warum sollte ich so etwas Abwegiges glauben? Ich weiß ja, wie TCP/IP
funktioniert. Deswegen benutze ich Fachausdrücke wie "Fragmentierung"
auch nicht falsch.
> Kurz: TCP garantiert dir, dass deine Bytes in der richtigen Reihenfolge> ankommen, aber weder der Kernel, noch Python, noch irgendeine RFC> garantieren dir, dass jedem "write" beim Sender exakt ein "read" beim> Empfänger entspricht.
Ja, natürlich, das ist die Idee hinter TCP, das ist ja kein UDP. Aber
dieses Verhalten hat nichts mit Fragmentierung zu tun.
Weisst du, das Missverständnis hätte sich vermeiden lassen. Du musst
immer daran denken, wie andere das was du Sagst verstehen werden. Es
entstand der Eindruck, dass du die kompletter Aussage ablehnst, nicht
nur das Beispiel für einen Fall, wo die Problematik eintreten kann. Du
hättest einfach sagen können, es stimmt dass X, aber Y hat nichts damit
zu tun. Statt dem hier:
Ein T. schrieb:> Bitte informiere Dich, was ein Betriebssystemkernel mit empfangenen> TCP-Fragmenten macht, bevor er sie an den Userspace weitergibt. Und> bitte gib niemandem mehr einen "Rat" in diesen Dingen, bevor Du es nicht> absolut sicher weißt. Vielen Dank.
Was hast du erwartet, wie andere das hier verstehen würden?
Und besonders nett war es auch nicht, du stellst damit seine Kompetenz
in frage, wegen solch einer Belanglosigkeit. Das ist auch nicht gut für
dein soziales Ansehen. Wenn andere sehen, wie du jemanden so behandelst,
könnten sie dich für ein Arschloch halten. Naja, Morgen wird sicher ein
besserer Tag.
Daniel A. schrieb:> Weisst du, das Missverständnis hätte sich vermeiden lassen. Du musst> immer daran denken, wie andere das was du Sagst verstehen werden.
Ja, natürlich. Der ursächliche Fehler lag und liegt aber nicht bei mir,
sondern bei dem Herrn, der in diesem Zusammenhang den Fachausdruck
"Fragmentierung" mißbraucht hat.
> Ein T. schrieb:>> Bitte informiere Dich, was ein Betriebssystemkernel mit empfangenen>> TCP-Fragmenten macht, bevor er sie an den Userspace weitergibt. Und>> bitte gib niemandem mehr einen "Rat" in diesen Dingen, bevor Du es nicht>> absolut sicher weißt. Vielen Dank.>> Was hast du erwartet, wie andere das hier verstehen würden?
So, wie es da steht: nämlich, daß das besagte Verhalten nichts mit
Fragmentierung zu tun hat. Ich habe diesen Fachausdruck sogar zitiert
und damit verdeutlicht, daß es genau um diesen Punkt gint.
> Und besonders nett war es auch nicht, du stellst damit seine Kompetenz> in frage, wegen solch einer Belanglosigkeit.
Wer Fachausdrücke mißbraucht, muß sich die Frage nach seiner Kompetenz
gefallen lassen. Die Formulierung von Ernst war: "Aber: es ist nicht
gesagt, dass jedes "read" exakt einem "write" an der Gegenstelle
entspricht."
Das stimmt bis hierher. Aber dann folgt seine Erklärung:
"Das Packet könnte fragmentiert worden sein, dann kriegst du die Daten
evtl. auf mehrere reads verteilt, oder es könnten mehrere writes
zusammengefasst worden sein (NAGLE am Server), dann kommen in einem read
mehrere "Nachrichten" auf einmal."
Er erklärt den vorgenannten Umstand also direkt mit der Fragmentierung,
und das ist, egal, wie man es dreht und wendet, schlicht und ergreifend:
falsch. Deswegen habe ich ihn freundlich gebeten, sich in diesem
Zusammenhang nochmals über die Funktion des kernelseitigen IP-Stack zu
informieren und sich mit Ratschlägen an Dritte bitte zurückzuhalten, bis
er das getan hat. Wer sich von solchen freundlichen Bitten angegriffen
fühlt, der will sich wohl angegriffen fühlen. Aber Pardon, dafür bin
dann nicht mehr ich verantwortlich.
Ein T. schrieb:> [...]
Heulst du eigentlich gleichermaßen bei Netzwerkprotokollen rum, die den
Begriff Fragmentierung benutzen, damit aber gar nicht IP-Fragmentierung
meinen?
Jemand schrieb:> Ein T. schrieb:>> [...]>> Heulst du eigentlich gleichermaßen bei Netzwerkprotokollen rum, die den> Begriff Fragmentierung benutzen, damit aber gar nicht IP-Fragmentierung> meinen?
Lieben Dank für Deinen überaus wertvollen Beitrag zur Diskussion.
Ein T. schrieb:> Das stimmt bis hierher. Aber dann folgt seine Erklärung:> "Das Packet könnte fragmentiert worden sein, dann kriegst du die Daten> evtl. auf mehrere reads verteilt, oder es könnten mehrere writes> zusammengefasst worden sein (NAGLE am Server), dann kommen in einem read> mehrere "Nachrichten" auf einmal."> Er erklärt den vorgenannten Umstand also direkt mit der Fragmentierung,> und das ist, egal, wie man es dreht und wendet, schlicht und ergreifend:> falsch.
Na ja. Wann kommt denn ein UDP-Paket NICHT in einem Rutsch im Userspace
an? IP reassembly hat damit direkt nichts zu tun. Aber so ein Fall kann
auftreten wenn Empfangspuffer zu klein sind, also bei grossen Paketen.
Und grosse Pakete werden eher in mehrere frames fragmented und
reassembled als kleine.
Ich fand den Rat von Ernst, bis auf die ungenaue Begründung, recht
hilfreich. Und ich empfinde eine Aufforderung, solche Hilfe wegen eines
Details zu unterlassen, als recht arrogant. Aber YMMV.
LG, Sebastian
Sebastian schrieb:> Na ja. Wann kommt denn ein UDP-Paket NICHT in einem Rutsch im Userspace> an? IP reassembly hat damit direkt nichts zu tun. Aber so ein Fall kann> auftreten wenn Empfangspuffer zu klein sind, also bei grossen Paketen.
Das ist aus mehreren Gründen ein anderer Fall: erstens geht es hier im
TCP, zweitens geschieht die IP-Fragmentierung nunmal im IP-Protokoll,
also auf der Netzwerkschicht unterhalb des UDP-Protokolls. Um
IP-Fragmentierung und -Reassembly kümmert sich der IP-Stack im Kernel
des Betriebssystems -- in einem Linux-Kernel Version 5.4 in der Funktion
ip_local_deliver() (net/ipv4/ip_input.c:240), die ihrerseits wiederum
ip_is_fragment() (include/net/ip.h:386) und ip_defrag()
(net/ipv4/ip_fragment.c:474) verwendet, um zu prüfen, ob ein IP-Paket
fragmentiert ist, und es defragmentiert, wenn dies der Fall ist. All das
findet unterhalb der UDP- auf der IP-Schicht anhand des IP-Feldes
"Identification" im 5. und 6. Byte des IP-Headers statt.
> Ich fand den Rat von Ernst, bis auf die ungenaue Begründung, recht> hilfreich. Und ich empfinde eine Aufforderung, solche Hilfe wegen eines> Details zu unterlassen, als recht arrogant. Aber YMMV.
Das Problem ist halt, daß sich so etwas dann festsetzt. Mir sind schon
eine ganze Reihe von Benutzern mit falschen, dennoch aber felsenfesten
Überzeugungen über den Weg gelaufen, die sich nicht einmal durch
Verweise auf einschlägige Fachliteratur, die korrekten RFCs oder dem
Zeigen des entsprechenden Kernelcode von ihren falschen Vorstellungen
abbringen ließen. Wenn man mit solchen Leuten gemeinsam eine Lösung
finden muß, kann das sehr enervierend werden. Deswegen halte ich es
besonders bei Anfängern für sinnvoll, einen gewissen Wert auf
Korrektheit zu legen.
Ein T. schrieb:> erstens geht es hier im> TCP, zweitens geschieht die IP-Fragmentierung nunmal im IP-Protokoll,> also auf der Netzwerkschicht unterhalb des UDP-Protokolls.
So, und jetzt denk etwas weiter, das Gesamtsystem betrachten.
Was könnte die Ursache für die IP-Fragmentierung sein?
Was ist eine "path mtu discovery"?
Wieso hat jetzt auf einmal ICMP was damit zu tun?
Welchen Einfluss hat diese MTU auf die TCP MSS?
Welchen Einfluss könnte die TCP MSS darauf haben, wie "reads" und
"writes" auf Sender- und Empfängerseite zusammenpassen?
Εrnst B. schrieb:> Was könnte die Ursache für die IP-Fragmentierung sein?> Was ist eine "path mtu discovery"?> Wieso hat jetzt auf einmal ICMP was damit zu tun?> Welchen Einfluss hat diese MTU auf die TCP MSS?> Welchen Einfluss könnte die TCP MSS darauf haben, wie "reads" und> "writes" auf Sender- und Empfängerseite zusammenpassen?
Ich empfehle Dir gerne entsprechende Fachliteratur, wenn Du möchtest.
Ein ganz guter Einstieg ist "Computer Networks" von Andrew S. Tanenbaum
(ja, dieser Tanenbaum).
Und ich empfehle dir, es einfach mal auszuprobieren.
Schnapp dir strace und netcat, wie Daniel, bastel dir eine Verbindung
mit verstellbarer MTU dazwischen, und Teste.
Und wenn du dann feststellst, dass die MTU und damit IP-Fragmentierung
doch einen Einfluss auf TCP haben, kannst du ja immer noch deine
Fachliteratur und die Linux-Sourcen nach dem Grund dafür durchforsten.
Ein T. schrieb:> Das Problem ist halt, daß sich so etwas dann festsetzt.
Das mag sein, aber dass muss jeder selbst lernen, dass man nicht alles
für bare münze nehmen kann. Tatsächlich ist es so, dass so ziemlich jede
nicht-tautologische Aussage falsch, ungenau, oder in gewissen fällen
nicht richtig, ist. Ich habe noch nie eine Erklärung gesehen, die
unbestreitbar richtig wäre.
Nur schon was mir in der Schule alles für Blödsinn erzählt wurde.
Elektronen umkreisten Atome (keiner weiss so genau, wie man sich diese
X-dimensinale Wahrscheinlichkeitswolken am besten vorstellt). a^2 + b^2
= c^2 (das Universum ist nicht euklidisch). Die Erde ist eine Kugel
(Eher ein Rotationsellipsoid, aber auch nur näherungsweise). CPUs führen
Instruktionen aus (sieh führen heutzutage Microcode aus. Wobei, auch das
ist eine Simplifizierung). Hardware ist Physisch (dann lernt man von
FPEGAs). etc.
Kann man endlos weiterführen. Dass muss jeder für sich selbst lernen,
dass nie etwas komplett richtig ist. Man kann nichts wissen. Man kann
nur sein Verständnis von Sachverhalten verbessern. Schritt für schritt.