non-blocking sockets - HTTP - Client-Seitig



  • Hallo,

    man braucht non-blocking Sockets als Klient für eine HTTP-Antwort, weil man sich nicht auf die Content-Length basieren soll.

    Also wenn ich das richtig verstanden habe, muss man sich bei non-blocking Sockets auf Timeouts basieren, stimmt das? Für non-blocking Sockets benutzt man doch idR select(), man kann aber auch recv() benutzen.

    Bei recv() bedeutet eine Rückgabe von EAGAIN oder EWOULDBLOCK, dass die Funktion blockieren würde. Ergo entweder man empfängt zu früh und man bekommt EAGAIN, oder man hat tatsächlich alles empfangen und man bekommt EAGAIN. Einen Unterschied zwischen den beiden kann man nicht machen. Und genau das ist mein Problem.

    Ich kann mich gerade nicht damit abfinden, dass ich mit Timeouts arbeiten soll, weil das doch erheblich die Performance (so um gefühlt 0,5 - 1 Sekunde) beeinträchtigt.

    Bevor ich das ganze Zeug also mit Timeouts implementiere, wollte ich hier mal nachfragen, nur um auf Nummer sicher zu gehen.

    Ich dachte eigentlich ständig man kann sehr wohl definieren wann das Lesen bei non-blocking Sockets endet, man kann sich jedoch nicht auf EAGAIN verlassen, weil wie bereits gesagt, empfängt man zu früh bekommt man auch EAGAIN.

    Ergo man kann bei non-blocking Sockets nicht definieren wann Anfang und Ende ist, sondern man muss warten. Und wenn man nach dem Warten nichts bekommen hat, so "vermutet" man einfach, dass alles angekommen ist, was dann auch wohl zu 99% immer der Fall sein wird.

    Nun angenommen ich schreibe ein Programm, das eine HTTP-Antwort (eine einzige) empfängt, die Daten bearbeitet und das Resultat ausspucht - Programm Ende. Wenn ich das sauber mit Nonblocks machen will, dann habe ich einige Bruchteile einer Sekunde verpatzt, nur weil ich warten musste, bis das Timeout endet.

    Soll das so wirklich richtig sein...?



  • Blockade schrieb:

    man braucht non-blocking Sockets als Klient für eine HTTP-Antwort, weil man sich nicht auf die Content-Length basieren soll.

    Ist deine Muttersprache deutsch?

    Blockade schrieb:

    Also wenn ich das richtig verstanden habe, muss man sich bei non-blocking Sockets auf Timeouts basieren, stimmt das? Für non-blocking Sockets benutzt man doch idR select(), man kann aber auch recv() benutzen.

    Ich verdoppel' meine Frage. Hast du dir die Doku zu Sockets durchgelesen? Wenn ja: was genau hast du nicht verstanden?

    Wenn du nicht auf den TCP-Timeout warten willst, weil der vom OS vorgeben wird und standardmäßig echt groß ist, dann musst du deinen eigenen Timeout definieren. Welches ENAPI (Event Notification API) du da jetzt verwendest, ist relativ egal, zumindest wenn du nicht ein völlig kaputtes (wie kqueue oder so) verwendest. 'nen Timeout kannst du sowohl bei select wie auch epoll_wait angeben. Das ist aber komplett unabhängig davon, ob dein Socket jetzt blockiert oder nicht!

    Warum? Was macht ein blocking Socket bei einem read/recv ? Er wartet, bis Daten ankommen. Notfalls bis zum erwähnten TCP-Timeout, bei dem der Leseversuch dann abgebrochen wird. Aber ansonsten hängt er dann da. Und macht nichts.

    Was macht ein non-blocking Socket bei einem read/recv ? Er wartet nicht. Er kehrt direkt zurück, wenn es keine Daten gibt.

    Das erste Szenario ohne ENAPI sorgt dafür, dass du bei Timeouts nix machen kannst. Das zweite Szenario ohne ENAPI sorgt dafür, dass deine CPU-Last hochgeht. Beides ist scheiße. Für beides nimmst du ein ENAPI. Problem gelößt. Da braucht es keine Sonderfälle für das Lesen vom Socket.

    Blockade schrieb:

    Einen Unterschied zwischen den beiden kann man nicht machen. Und genau das ist mein Problem.

    Doch, kannst du. Du redest ja hier von HTTP-Kommunikation. Also machst du bei jedem erfolgreichen Read von Socket eine Syntaxprüfung der Daten. Über ein State-Objekt kannst du bestimmte Daten cachen, die musst du dann nicht wieder und wieder und wieder einlesen, verifizieren usw. Sobald du genug Daten hast, signalisiert du das der Schleife, die die Daten von dem Socket ließt, damit sie aufhört.

    An der Syntaxprüfung kommst du nicht vorbei. An der Syntaxprüfung kommst du nicht vorbei! Musst du machen. Also zuerst ENAPI, damit du bei zu langen Durststrecken abbrechen kannst, und dann Syntaxprüfung, damit du weißt, wann die andere Seite tatsächlich nix mehr zu sagen hat. Dann sind auch die "Performancebeeinträchtigungen" weg.



  • Man braucht erst mal keine non blocking Sockets für eine HTTP-Antwort. Es gibt 3 Möglichkeiten, wie das Ende der HTTP-Antwort aussehen kann. Allerdings hängt das weitestgehend vom Server ab, welche er verwendet.

    Möglichkeit 1: HTTP/1.0: Im Http-Header steht die Version 1.0. Dann ist die Antwort abgeschlossen, sobald der Server die Verbindung schließt.

    Möglichkeit 2: HTTP/1.1 mit Content-Size: Da steht tatsächlich die Anzahl der Bytes vom Body im Header. Dann kannst Du Dich darauf verlassen.

    Möglichkeit 3: Chunked-Encoding: Der Server schickt so Blöcke mit einem Längenheader. Ein Block mit der Länge 0 schließt den Body ab.

    In keinem Fall brauchst Du not blocking Sockets. Außer Dein Client will auf Timeouts reagieren, also für den Fall vorbereitet sein, dass der Server aus irgendeinen Grund nicht antwortet.

    Details über HTTP kannst Du im RFC 2616 nachlesen.

    Was willst Du erreichen? Brauchst Du einen Client für ein Projekt oder willst Du nur Netzwerkkommunikation üben? Im ersten Fall solltest Du eine fertige Library nehmen, da ein robuster HTTP-Client alles andere als trivial ist.

    Ich empfehle natürlich meine cxxtools. Kannst aber auch libcurl oder Poco oder was auch immer nehmen.



  • tntnet schrieb:

    Möglichkeit 2: HTTP/1.1 mit Content-Size: Da steht tatsächlich die Anzahl der Bytes vom Body im Header. Dann kannst Du Dich darauf verlassen.

    Nein, kannst du nicht. Sende ich zu wenig Bytes, blockiere ich damit zumindest den Socket Thread. Sende ich zu viele Bytes, kann ich bei mangelhafter Programmierung (die ich durch deine Aussage bereits in meinem Kopf inspiriert sehe) einen Overflow erzeugen.

    Unabhängig davon kann es sein, dass du zu wenig Daten bekommst, weil gerade die Verbindung mies ist oder so. Oder der Server unterstützt Pipelining und sendet mehrere Antworten in einem Batch. Deswegen: NICHT verlassen. Nimm die Content-Length (nicht Content-Size!) als Hinweis darauf, wie viele Bytes da ankommen müssen, aber verlasse ich nicht darauf, exakt diese Menge zu bekommen. Sonst kommst du schneller in Teufels Küche, als uns allen lieb ist.

    tntnet schrieb:

    In keinem Fall brauchst Du not blocking Sockets.

    Stimmt so auch nicht ganz. Gerade das select bei Linux ist radioaktive Ebola-Beulenpest in Tüten - da können fehlerhafte OOB-Daten ("Rauschen") die Funktion zurückkehren lassen, aber ein späterer read blockiert dann wieder. Wird so auch von den Kernel-Leuten verteidigt, der Geschwindigkeit wegen. Fix: mach doch einfach deinen Socket non-blocking!

    Kommt halt darauf an, wie sehr du um eine kaputte Funktion rumarbeiten willst.

    tntnet schrieb:

    Außer Dein Client will auf Timeouts reagieren, also für den Fall vorbereitet sein, dass der Server aus irgendeinen Grund nicht antwortet.

    Passiert auch so selten, wa?

    tntnet schrieb:

    Ich empfehle natürlich meine cxxtools. Kannst aber auch libcurl oder Poco oder was auch immer nehmen.

    Habe mir mal den Code kurz angeschaut. Verwendet Streams zum Buffern, und die sind natürlich auch privat. Man kann also nicht eigenen Speicher angeben, der nach Möglichkeit noch erweitert werden kann. Relokation ist daher sehr wahrscheinlich auch mit einer Kopie verbunden.

    deflate/gzip-Dekodierung wird nicht unterstützt? Denn de-chunken ohne weitere Kopie?

    Also so ganz überzeugt bin ich ja nicht ...



  • dachschaden schrieb:

    deflate/gzip-Dekodierung wird nicht unterstützt? Denn de-chunken ohne weitere Kopie?

    Also so ganz überzeugt bin ich ja nicht ...

    Ist deine Muttersprache deutsch? :p

    Na Dich muss ich ja nicht überzeugen 😉 Ich kann damit leben, dass Du mein Code nicht gut findest.



  • tntnet schrieb:

    Ist deine Muttersprache deutsch? :p

    In der Tat. Die Datenpakete bei "Transfer-Encoding: chunked" werden nun mal "Chunks" genannt, das Entfernen der Chunk-Header ist daher das "de-chunken".

    Dass man sich auf irgendwelchen Werten nicht "basieren" sollte, habe ich allerdings noch nie gehört. Der korrekte Ausdruck wäre hier "festlegen" oder "vertrauen".

    Und das "denn" leitet eine zweite Frage ein, wenn man die erste Frage negativ beantwortet erwartet.

    tntnet schrieb:

    Na Dich muss ich ja nicht überzeugen 😉 Ich kann damit leben, dass Du mein Code nicht gut findest.

    Ja, ein Glück, dass das Runterschrauben der eigenen Ansprüche so leicht geht. Nicht auszudenken, wenn da ordentliche Arbeit hinterstehen würde.



  • tntnet schrieb:

    dachschaden schrieb:

    deflate/gzip-Dekodierung wird nicht unterstützt? Denn de-chunken ohne weitere Kopie?

    Also so ganz überzeugt bin ich ja nicht ...

    Ist deine Muttersprache deutsch? :p

    Wie wäre es, wenn Du ganze und möglicherweise sogar verständliche Sätze schreiben würdest? "Denn de-chunken ohne weitere Kopie?" verstehe ich als Satz schon gar nicht. Ich weiß echt nicht, was Du damit meinst.

    Und wenn "Anspruch runter schrauben" bedeutet, dass ich ausgerechnet Dich nicht überzeugen muss, dann sei es so.



  • tntnet schrieb:

    Wie wäre es, wenn Du ganze und möglicherweise sogar verständliche Sätze schreiben würdest?

    Du bist der erste, der sich darüber beschwert hat. Ich gehe daher davon aus, dass es deine Deutschkenntnisse sind, die hier mangelhaft sind.

    tntnet schrieb:

    "Denn de-chunken ohne weitere Kopie?" verstehe ich als Satz schon gar nicht. Ich weiß echt nicht, was Du damit meinst.

    Für den Fall, dass es am Deutsch hapert: siehe oben.

    Für den Fall, dass dir der Umstand nur nicht bewusst ist: damit meine ich, ob dein Code es schafft, die Chunk-Header zu entfernen, ohne dass du dafür ein neues Feld alloziieren musst?

    tntnet schrieb:

    Und wenn "Anspruch runter schrauben" bedeutet, dass ich ausgerechnet Dich nicht überzeugen muss, dann sei es so.

    Also, was denn jetzt? Wenn man eine eigene Library schreibt, die man dann noch anderen empfiehlt, dann muss diese mehrere objektive Voraussetzungen erfüllen:

    1. Die Interfaces müssen offensichtlich sein.
    2. Es muss einfacher sein, die APIs richtig zu benutzen, als sie falsch zu benutzen.
    3. Die Implementation darf keine Zweifel lassen, dass "ich mach das mal schnell von Hand" keine Vorteile und nur Nachteile hat.
    4. Insbesondere muss die Performance besser sein, als man das mal eben selber hingekriegt hätte.

    Nummer 1 sehe ich hier nicht gegeben - was alleine der Konstruktor verbricht, habe ich bereits geschrieben.
    2 - habe ich nicht geprüft, lasse ich also offen.
    3 - auch hier wieder deine Konstruktoren. Wo ich sogar vor zwei Posts geschrieben habe, was man besser hätte machen können.
    4 - und auch hier wieder, deine Konstruktoren. Was meinst du, warum ich die als Beispiel genommen habe?

    Es gibt nur einen Grund, warum man deinen Code verwenden sollte, und der ist, dein Ego zu befriedigen. Und genau darum geht es hier - dein Ego, welches sich einredet, dass deine Library gut genug ist. Weil du auf halben Weg gesagt hast, dass es schon gut genug sein wird. Warum sonst lässt du diese Eiterbeulen da drin und empfiehlst sie dennoch?

    Ich brauche deinen Code nicht. Dein Code ist mir komplett egal. Ich habe meinen eigenen, den ich aber nicht Leuten empfehle. Aber wenn du anfängst, anderen deinen Code zu empfehlen, und dann sind dieses Eiterbeulen da drin, dann hörst du den Donner von mir. Vor allem dann, wenn meine Kritik mit "es muss dir aber nicht reichen!1!!" beantwortet wird.

    "Streamobjekte reiche ich derzeit nicht durch, könnte ich beizeiten mal einfügen" - bamm, bin ich schachmatt.
    "Speicherallokationen in C++ sind scheiße, wenn man was ordentliches haben will, ist das halbes C und man wird dafür ausgebuht. Deswegen geht Relokation nur mit Kopie" - kann ich verstehen. Sogar gut. Hätte ich auch keine Munition gegen.
    "Ich könnte den Speicher, in dem der Content drin ist, behalten und Chunk-Header einfach mit memmove überschreiben" - genau das mache ich auch. Keine weitere Kopie. Kann wahrscheinlich direkt im CPU-Cache gemacht werden und sollte rasendschnell gehen.

    Stattdessen bekomme ich die Antwort, dass du dir "ist schon gut genug" herbeihalluzinierst. Aber dann anderen es empfehlen. Warum ich darauf so rumreite? Weil Anfänger keinen Plan davon haben, wie gut Code ist. Passiv anbieten - kann man machen. Aktiv empfehlen - nur dann, wenn die obigen Kriterien erfüllt sind.

    Niemand geht los, um langsame Software zu schreiben. Aber auf dem Weg brechen viele Leute ab, weil ihnen gesagt wird, die Dinge seien "schnell genug". Oder weil sie es sich selbst sagen.



  • dachschaden schrieb:

    tntnet schrieb:

    "Denn de-chunken ohne weitere Kopie?" verstehe ich als Satz schon gar nicht. Ich weiß echt nicht, was Du damit meinst.

    Für den Fall, dass es am Deutsch hapert: siehe oben.

    Für den Fall, dass dir der Umstand nur nicht bewusst ist: damit meine ich, ob dein Code es schafft, die Chunk-Header zu entfernen, ohne dass du dafür ein neues Feld alloziieren musst?

    Also gut. Ein deutscher Satz besteht in der Regel aus einem Subjekt, Prädikat und Objekt.

    "Denn de-chunken ohne weitere Kopie?"

    Also "de-chunken" ist ein Verb. Das ist wohl das Prädikat. "ohne weitere Kopie" sieht aus, wie ein Objekt. Ach ich verstehe diesen Satz einfach nicht. Der ist mir wohl zu schwer. Na dann entschuldige ich mich für meine mangelnden Deutschkenntnisse. Und dafür, dass ich meine Library empfohlen habe.

    cxxtools::http::Client client("www.tntnet.org", 80);
       std::string indexPage = client.get("/");
    

    Ich habe mir Mühe gegeben, das Interface so einfach wie möglich zu gestalten. Ich weiß nicht, wie ich das vereinfachen könnte. Da fehlen mir wohl die Deutschkenntnisse.

    Ich danke für Deine ausführliche Kritik an meinem Code. Ich werde es in meinen zukünftigen Projekten beachten. Insbesondere werde ich zukünftig nicht mehr einfach so unbedacht de-chunken.



  • tntnet schrieb:

    Also gut. Ein deutscher Satz besteht in der Regel aus einem Subjekt, Prädikat und Objekt.

    Ja, genau. Jetzt misch noch Haupt- und Nebensätze in einen Pott. Ist ja nicht so, dass sie einem im Deutschunterricht jede Woche eintrichtern, dass Nebensätze ohne auf sie referenzierende Hauptsätze nicht alleinstehen können. Dass du dies nicht weißt, ist ja nicht mal mit Abendschuldeutsch zu erklären; das muss komplette Arbeitsverweigerung gewesen sein.

    Also, jetzt mal Deutsch für Hauptschüler: Der Hauptsatz ist hier:

    "deflate/gzip-Dekodierung wird nicht unterstützt?"

    , welcher außerdem eine Frage ist. Präsenz Passiv, "unterstützen" ist das Verb hier.

    Der Nebensatz ist:

    "Denn de-chunken ohne weitere Kopie?"

    Würde man ihn in seinen eigenen Hauptsatz umwandeln, wäre dieser:

    "Wird denn de-chunken ohne weitere Kopie unterstützt?"

    Wenn man kein Sprachgefühl besitzt, dann stört es einen natürlich nicht, dass das gleiche Verb in zwei aufeinanderfolgenden Sätzen verwendet wird, ohne dass hierbei eine rhetorische Wirkung beabsichtigt ist:

    "deflate/gzip-Dekodierung wird nicht unterstützt? Wird denn de-chunken ohne weitere Kopie unterstützt?"

    Und ich verstehe auch, dass es eine Doktorarbeit in fortgeschrittener Germanistik benötigt, um zu begreifen, dass man Konjugationen im Deutschen weglassen kann, solange die Relation von Haupt- und Nebensatz deutlich ist. Mit einer Konjugation wäre diese:

    "deflate/gzip-Dekodierung wird nicht unterstützt, genauso wie de-chunken ohne weitere Kopie?"

    Aber anscheinend kann bei dir der Fokus des Hauptsatzes nicht erhalten werden, wenn es einen Punkt zwischen beiden Sätzen gibt. Aber selbst Abendschulverweigerer sollten erkennen, dass Haupt- und Nebensätze getrennt sein können, solange nur der Nebensatz auf den Hauptsatz referenziert:

    "deflate/gzip-Dekodierung wird nicht unterstützt? Genauso wie de-chunken ohne weitere Kopie?"

    Die besondere Ironie ist, dass ich des öfteren Rechtsschreibfehler tippe. Auf diesen hättest du, zwar ein wenig kleinlich, aber wenigstens berechtigt rumreiten können. Aber wer nie ein ordentliches Sprachgefühl entwickelt hat, der würde diese wahrscheinlich auch gar nicht erkennen.

    tntnet schrieb:

    cxxtools::http::Client client("www.tntnet.org", 80);
       std::string indexPage = client.get("/");
    

    Wo gebe ich den Buffer für das HTTP-Header-Array? Werden die Header vordefiniert? Kann ich zwei Arrays angeben, einmal mit den Namen, dann mit den Werten, die beim HTTP-Request gesendet werden sollen? Habe ich präzise Kontrolle darüber, in welcher Reihenfolge welche Header in den Socket geschrieben werden (wichtig für Fingerprints von Browsern)?

    Was ist, wenn ich mich mit einem Host verbinden will, der mehrere virtuelle Hosts beherbergt? Wo ist das obligatorische Statusobjekt, in dem die Daten des Sockets reingeschrieben werden? Kann ich eine maximale Responsegröße anlegen? Warum muss ich Domain und Port beim Konstruktor angeben? Was, wenn das Objekt nicht angelegt werden konnte, weil z.B. gerade keine Verbindung besteht? Exceptions? Ernsthaft? Also Objekt auf dem Heap erstellen, Stack rewinden, Objekt auflösen?

    Was ist mit mehreren Namenstabellen? Wenn ich jetzt zum Beispiel will, dass mehrere Clients sich die gleichen Auflösungen teilen? Wenn das OS intelligent ist, wird gecacht, aber getaddrinfo ist sehr kaputt (benötigt freeaddrinfo ... ernsthaft jetzt?).

    Wie steht es mit deinem de-gzipper aus? Werden Daten größer als 4 GiB unterstützt?

    Was ist mit dynamischen HTTP-Header-Daten? Sagen wir mal, wenn du Content-Disposition[c] baust. Oder [c]Content-Length . Heap, wahrscheinlich, oder? Ohne Möglichkeit, meinen eigenen Buffer zwischenzuklemmen?

    Was, wenn ich über einen transparenten Proxy reingehen will/muss? Kann ich ein Protokoll angeben, über das versucht wird, mit dem Proxy zu reden? Kann ich auch meinen eigenen Socket verwenden lassen? Wie steht's mit Pipelining? Wie oft verwendest du komplett unnötig new und delete ?

    Was ist, wenn du Daten (Plural von Datum) schreiben musst? strftime oder eine Funktion, die sie abkapselt?

    tntnet schrieb:

    Ich habe mir Mühe gegeben, das Interface so einfach wie möglich zu gestalten.

    Du hast die Funktionalität stark eingeschränkt, um das Interface einfach halten zu können, ohne viel Arbeit reinzustecken. Wenn du auch nur bei 50% meiner Fragen sagen kannst, dass das von dir exportierte Interface diese Sachen einfach und intuitiv erlaubt, dann fresse ich einen Besen.

    tntnet schrieb:

    Ich weiß nicht, wie ich das vereinfachen könnte. Da fehlen mir wohl die Deutschkenntnisse.

    Nee, die fehlen dir noch dazu.



  • Dann sage ich das mal so: Ich war früher recht aktiv hier im Forum. Es hat mir Spaß gemacht. Aber wegen solchen Kommentaren habe ich Abstand davon genommen.

    Ich habe versucht, den Fragesteller eine einfache Antwort zu liefern, womit er eventuell etwas anfangen kann. Aus seiner Frage entnehme ich, dass er nicht der Vollprofi ist, der sich mit Allokationen und was auch immer auskennt.

    Leider bekommt er als Reaktion eine Frage, ob er denn überhaupt ausreichend Deutschkenntnisse halt. Schade. Das wird ihn wohl nicht wirklich motivieren.

    Ich bekomme auf meinen Kommentar mit dem unbedachten Hinweis, dass ich so was schon mal gemacht habe und meine Lösung auch einsehbar ist die nächste Breitseite. Mein Code wäre schlecht.

    Du erwartest jetzt wirklich, dass ich da anfange, meinen Code zu verteidigen? Wenn jemand echtes Interesse an meinem Code zeigt, bin ich gerne bereit, darüber zu diskutieren. Aber wenn ich so angegriffen werde, dass das doch alles sehr dürftig ist, dann lass ich es eben.

    Ich könnte die eine oder andere Frage von Dir beantworten. Ich lasse es lieber, da Du nicht den Eindruck machst, als hättest Du echtes Interesse.

    Wenn Du meinen Code richtig schlecht findest, dann ist das eben so. Das ist völlig in Ordnung. Wenn Du meine Deutschkenntnisse bemängelst, dann ist das auch ok. Ich komme hier mit meinen Deutschkenntnissen gut zurecht. Übrigens ist meine Muttersprache tatsächlich nicht deutsch, aber das ist egal.

    Und jetzt denke ich, sollten wir es dabei belassen. Das hat schon lange nichts mit Linux zu tun.



  • Ja chillt doch mal eure Nippel.

    Meine Frage wurde an sich beantwortet, ich muss entweder mit Timeouts arbeiten oder ich parse die Response Stück für Stück und hör halt dann auf, wenn alles angekommen ist.

    Auf die Content-Length darf man sich nicht basieren, die muss nicht mitgeschickt werden und hab auch schon erlebt, dass die um einige Bytes ungenau war.

    Eigentlich bin ich recht zufrieden mit curl und Boost.Asio, ich dacht mir doch bloß, dass ich meinen Penis mal etwas tiefer in Sachen Netzwerkeln dippe und selbst was bau.

    Aber ich bleib dann doch noch lieber bei Boost.Asio, weil mich das mit dem State-Objekt bis jetzt noch ein wenig verwirrt, bzw. noch nicht so richtig darauf gekommen bin eine Parsing-Routine einfach mal so in der Mitte zu pausen und sie danach - wenn mehr Daten da sind - genau an der selben Stelle wieder weiterzuparsen. Also zumindest was der Response-Body angeht (das, was nach dem Header kommt).

    tntnet, ich hab mir die Lib nicht angesehen, aber mit den zwei Zeilen kommt man ja schon ziemlich schnell an sein Ziel. Was du noch machen könntest, wäre weiter zu abstrahieren. Mach aus deinem Client ein "HttpRequest" und leite dann weitere Klassen ab, die spezifischer sind (GetRequest, PostRequest, HeadRequest, etc.).

    Dann würde ich noch ein Template daraus machen, damit du einen Aggregat des Response-Buffers in deiner Client-Klasse hast. Dann musst du dir halt noch einige Helfer-Funktionen schreiben, die das direkt vom char* aus in die gewünschte Struktur kloppt. Spezialisierte Funktoren würde ich da verweden. Eine Kopie damits zur richtigen Struktur geformt wird, wird man ja wohl noch machen dürfen.

    Wie wärs mit... *reinpfusch*:

    std::string buffer;
    cxxtools::http::get_request<std::string> request(buffer, url, port);
    request.rattern();
    std::cout << "pluff: " << buffer;
    


  • tntnet schrieb:

    Dann sage ich das mal so: Ich war früher recht aktiv hier im Forum. Es hat mir Spaß gemacht. Aber wegen solchen Kommentaren habe ich Abstand davon genommen.

    Du meinst, weil Leute einen nicht mehr mit jedem Scheiß davonkommen lassen? Ja, traurig. Weil Kritik ja auch auf keinen Fall anregen kann, es besser zu machen ...

    Außerdem verstehe ich den Wert eines Fachforums durch seine Größe nicht. Wenn man Größe dadurch erkauft, dass keine Kritik mehr geäußert werden kann, dann bleibe ich lieber ganz weg.

    Sorry, da hättest du deinen Post genauso gut mit "Aber meine Gefühle ..." beginnen können. Dann wäre es wenigstens offensichtlich gewesen.

    tntnet schrieb:

    Leider bekommt er als Reaktion eine Frage, ob er denn überhaupt ausreichend Deutschkenntnisse halt. Schade. Das wird ihn wohl nicht wirklich motivieren.

    Was glaubst du, wie egal mir das ist?

    Es ist nichts schlimmes daran, kein Muttersprachler zu sein. Nur ein Hinweis am Anfang wäre schön gewesen, damit man weiß, dass man hier tatsächlich Nachsicht üben kann.

    Und wenn er tatsächlich Muttersprachler ist, dann ist das ein Wink mit dem Zaunpfahl, dass er keine Wörter verwenden soll, die er nicht kennt. Letztens erst hier jemanden gesehen, der realloc verwenden wollte, aber "implementieren" schrieb. Und wenn du den Leuten nicht unmissverständlich klar machst, dass das Blödsinn ist, dann machen die das wieder hier.

    Wenn sie dann abhauen, dann machen sie das vielleicht wieder - aber zumindest nicht hier. In beiden Fällen gewinne ich. Ganz einfach.

    tntnet schrieb:

    Ich bekomme auf meinen Kommentar mit dem unbedachten Hinweis, dass ich so was schon mal gemacht habe und meine Lösung auch einsehbar ist die nächste Breitseite. Mein Code wäre schlecht.

    Das habe ich nicht geschrieben.

    Da mache ich mir die Mühe, lade deinen Code runter, schaue ihn mir ein bisschen an und mache Anmerkungen. Ich stelle Fragen. Das "Also so ganz überzeugt bin ich ja nicht ..." wäre die ideale Einleitung für dich gewesen - du schließt sie für dich ab mit einem Gefühlstrip. Anstatt darauf einzugehen - oder einfach nur zu sagen: "Ja, hast recht" - implizierst du, dass subjektive Kriterien wichtiger sind als objektive.

    Geht's noch?

    tntnet schrieb:

    Du erwartest jetzt wirklich, dass ich da anfange, meinen Code zu verteidigen?

    Nicht mehr. Die echte Chance dazu hattest du. Wegen deinem Ego-Trip hast du sie verspielt.

    tntnet schrieb:

    Wenn jemand echtes Interesse an meinem Code zeigt, bin ich gerne bereit, darüber zu diskutieren. Aber wenn ich so angegriffen werde, dass das doch alles sehr dürftig ist, dann lass ich es eben.

    Manchmal denke ich mir: so oft, wie du bei anderen Halluzinationen siehst - kann das nicht sein, dass du ihnen auch unterliegst?

    Aber das Gute an einem Forum ist, dass die Sachen da niedergeschrieben sind. Da kann man verlinken. Zitieren. Man kann noch mal seine eigenen Worte durchlesen.

    Also, ja, du halluzinierst gerade. Fett.

    tntnet schrieb:

    Ich könnte die eine oder andere Frage von Dir beantworten. Ich lasse es lieber, da Du nicht den Eindruck machst, als hättest Du echtes Interesse.

    In der Sekundarstufe würde ich sowas mit "Renn' heim zu Mutti!" kommentieren.

    Aber wir sind ja erwachsen. Also, Hände auf den Tisch: ich habe echtes Interesse daran, was dein Interface so kann. Beantworte die Fragen. Ich werde sie mir durchlesen.

    tntnet schrieb:

    Wenn Du meinen Code richtig schlecht findest, dann ist das eben so. Das ist völlig in Ordnung.

    Und wieder, Halluzinationen.

    Wo habe ich geschrieben, dass ein Code schlecht ist? Was ich geschrieben habe, war:

    dachschaden schrieb:

    Ja, ein Glück, dass das Runterschrauben der eigenen Ansprüche so leicht geht. Nicht auszudenken, wenn da ordentliche Arbeit hinterstehen würde.

    Das hat per se nichts damit zu tun, was ich vom Code halte, sondern von der Arbeitseinstellung, die ich bei diesem Code zu sehen geglaubt habe. Und bei dieser Arbeitseinstellung würdest du auch zögern, das einfach mal so zu verwenden ... wenn man meine (zugegebenermaßen hohe) Erwartungshaltung mit der tatsächlichen Codequalität proportional verringern würde.

    tntnet schrieb:

    Wenn Du meine Deutschkenntnisse bemängelst, dann ist das auch ok. Ich komme hier mit meinen Deutschkenntnissen gut zurecht. Übrigens ist meine Muttersprache tatsächlich nicht deutsch, aber das ist egal.

    Dann hoffe ich, dass du durch meine (übertriebenen) Post etwas gelernt hast. Dennoch tut mir der letzte Post Leid. Du wusstest nicht, dass ich Muttersprachler bin, und ich wusste nicht, dass du's nicht bist.

    Nun erstmal back to topic ...

    Blockade schrieb:

    Meine Frage wurde an sich beantwortet, ich muss entweder mit Timeouts arbeiten oder ich parse die Response Stück für Stück und hör halt dann auf, wenn alles angekommen ist.

    Nein! Du musst beides machen:

    dachschaden schrieb:

    An der Syntaxprüfung kommst du nicht vorbei. An der Syntaxprüfung kommst du nicht vorbei! Musst du machen. Also zuerst ENAPI, damit du bei zu langen Durststrecken abbrechen kannst, und dann Syntaxprüfung, damit du weißt, wann die andere Seite tatsächlich nix mehr zu sagen hat.

    Und nach diesem Absatz - wie hätte ich das noch genauer formulieren sollen? Oder gilt hier nur: "Aus den Augen, aus dem Sinn", und ich hätte ich es in deinen Bildschirm brennen sollen?

    Blockade schrieb:

    Auf die Content-Length darf man sich nicht basieren

    OK, jetzt bist du nur ein lernunwilliger Ignorant. Schönes Wochenende noch.



  • Dude wo ist dein Scheißproblem.

    Du hast selbst all die Nachteile der Content-Length aufgelistet.

    Dass die Antwort vom Server geparst werden muss ist hier jedem klar. Wie man das gleichzeitig anstellt (Chunk empfangen -> Parse-Routine wieder zum leben erwecken -> wiederhole) war hier die Frage.



  • Blockade schrieb:

    Dude wo ist dein Scheißproblem.

    Dein Duktus, dein Textverständnis oder deine Lernunwilligkeit. Eines von den Dreien. Such's dir aus.

    Blockade schrieb:

    Du hast selbst all die Nachteile der Content-Length aufgelistet.

    ... was?

    Es geht hier doch nicht um Chunked-Transfer vs. Content-Length. In der Hinsicht ist Chunked-Transfer noch um einige Ecken beschissener als Content-Length, weil du bei Chunked-Transfer Daten nicht einfach so dumpen kannst. Wenn ich bspw. einen HTTP-File-Server schreiben wollen würde, dann würde ich der Einfachheit und Schnelligkeit wegen sendfile (Linux) / TransmitFile (Windows) verwenden, weil ich mir so die Kopie von Kernelspace in Userspace (Lesen der Datei) und die Kopie von Userspace in Kernelspace (Schreiben der Datei in den Socket) spare.

    Glaubst du, bei Chunked-Transfer kommen die HTTP-Daten genauso rein, wie die Chunks aufgeteilt werden? Der erste read/recv also die HTTP-Header, und dann jedes Mal einen Chunk? Oder in der Richtung? Probier's aus. Würde mich sehr stark wundern, wenn das klappen sollte - dazu bräuchte der Kernel nämlich einen HTTP-Parser (und ja, ich weiß, dass MS ihren Parser bei IIS in den Kernel getan hat).

    Wenn ich sage, du sollst dich nicht auf Content-Length verlassen, dann aus den gleichen Gründen, aus denen du dich nicht auf die Länge in den Chunk-Headern verlassen solltest. Weil auch mal zu wenig oder zu viel ankommen kann. Warum, habe ich bereits erläutert. Das Prinzip ist vergleichbar bei Heartbleed gewesen - der Ping dort konnte größer sein als der Payload, und der Pong konnte dann (1 << 16) - 1 Bytes an Fremddaten beinhalten. Wenn du genug hast, breche ab. Sag recv nicht, wie viel HTTP-Daten du noch erwartest, sondern wie viel du noch speichern kannst.

    Blockade schrieb:

    Dass die Antwort vom Server geparst werden muss ist hier jedem klar.

    Ach?

    Blockade schrieb:

    ich muss entweder mit Timeouts arbeiten oder ich parse die Response Stück für Stück und hör halt dann auf, wenn alles angekommen ist.

    Hört sich für mich so an, als ob du nur eines machen wolltest, während ich gesagt habe, dass du beides machen musst.

    Blockade schrieb:

    Wie man das gleichzeitig anstellt (Chunk empfangen -> Parse-Routine wieder zum leben erwecken -> wiederhole) war hier die Frage.

    my_result_code mrc;
    
    do
    {
        /*Syntaxüberprüfung für Pipelining.*/
        mrc = my_http_syntax_checker();
    
        if(mrc == MY_RESULT_CODE_ERROR)
        {
            /*Muss abgebrochen werden.*/
        }
    
        if(mrc == MY_RESULT_CODE_OK)
        {
            /*Muss anders abgebrochen werden, ohne Rollback.*/
        }
    
        /*Sieht gut aus, wir können weitermachen.
        **Prüfe, ob wir Daten haben über select.*/
        if(select() == NO_DATA) /*Oder so, schau dir die Doku an.*/
        {
            /*Timeoutbehandlung/Abbruch*/
        }
    
        /*Jetzt können wir endlich vom Socket lesen*/
        recv();
    }
    while(1);
    

    my_http_syntax_checker muss dann natürlich allerhand prüfen. Und weil das blöd ist, packst du bei jedem Call ein Cache-Objekt rein, über das my_http_syntax_checker dann weiß, welche Teile bereits überspringen werden können.

    HTTP ordentlich zu parsen ist halt leider nicht trivial.



  • dachschaden schrieb:

    tntnet schrieb:

    Ich bekomme auf meinen Kommentar mit dem unbedachten Hinweis, dass ich so was schon mal gemacht habe und meine Lösung auch einsehbar ist die nächste Breitseite. Mein Code wäre schlecht.

    Das habe ich nicht geschrieben.

    Da mache ich mir die Mühe, lade deinen Code runter, schaue ihn mir ein bisschen an und mache Anmerkungen. Ich stelle Fragen. Das "Also so ganz überzeugt bin ich ja nicht ..." wäre die ideale Einleitung für dich gewesen - du schließt sie für dich ab mit einem Gefühlstrip. Anstatt darauf einzugehen - oder einfach nur zu sagen: "Ja, hast recht" - implizierst du, dass subjektive Kriterien wichtiger sind als objektive.

    Geht's noch?

    tntnet schrieb:

    Du erwartest jetzt wirklich, dass ich da anfange, meinen Code zu verteidigen?

    Nicht mehr. Die echte Chance dazu hattest du. Wegen deinem Ego-Trip hast du sie verspielt.

    tntnet schrieb:

    Wenn jemand echtes Interesse an meinem Code zeigt, bin ich gerne bereit, darüber zu diskutieren. Aber wenn ich so angegriffen werde, dass das doch alles sehr dürftig ist, dann lass ich es eben.

    Manchmal denke ich mir: so oft, wie du bei anderen Halluzinationen siehst - kann das nicht sein, dass du ihnen auch unterliegst?

    Aber das Gute an einem Forum ist, dass die Sachen da niedergeschrieben sind. Da kann man verlinken. Zitieren. Man kann noch mal seine eigenen Worte durchlesen.

    Also, ja, du halluzinierst gerade. Fett.

    Eine Beleidigung nach der anderen. Du fängst gleich damit an, dem Originalposter zu fragen, ob er Muttersprachler ist. Damit wirfst Du ihm vor, er würde schlechtes Deutsch schreiben. Und dann kommt dieses "deflate/gzip-Dekodierung wird nicht unterstützt? Denn de-chunken ohne weitere Kopie? ", welches völlig falsches Deutsch ist. So falsch, dass man es nicht mehr versteht. Anstatt zu sagen: "ach ja - war in der Hektik unverständlich formuliert", verteidigst Du das noch. Das nenne ich Ego-Trip.

    dachschaden schrieb:

    Habe mir mal den Code kurz angeschaut. Verwendet Streams zum Buffern, und die sind natürlich auch privat. Man kann also nicht eigenen Speicher angeben, der nach Möglichkeit noch erweitert werden kann. Relokation ist daher sehr wahrscheinlich auch mit einer Kopie verbunden.

    Das ist keine Frage, sondern eine Annahme, dass man keinen eigenen Speicher angeben kann, was Du offensichtlich für unabdingbar hälst. Das unterstützt den Eindruck, dass Du den Code offensichtlich nicht gut findest.

    Das sind keine interessierten Fragen und keine konstruktive Kritik sondern einfach nur Kritik oder Nörgelei.

    Der Satz "Also so ganz überzeugt bin ich ja nicht ..." ist keine ideale Einleitung sondern eine Herausforderung. Du hoffst, dass ich ein so großes Ego habe, dass ich da drauf springen muss.

    Ich reagiere nicht, indem ich mich verzweifelt erkläre, wie man es bei einem Ego-Trip machen würde, sondern lasse es einfach so stehen und akzeptiere das. Also genau das Gegenteil vom Ego-Trip, den Du mir vorwirfst.

    Du wirfst mir eine schlechte Arbeitseinstellung vor. Auch wieder offensichtlich mit dem Ziel, mich zu beleidigen. Das sieht wirklich nicht nach Interesse aus.

    Ok - Dann nehme ich mal an, Du willst wirklich wissen, was cxxtools so kann.

    Ja, es kann chunked decoding ohne Kopien. Es kann non blocking http requests über eine Event loop. Es prüft alle Fehlercodes von Systemaufrufen und reagiert darauf. Es reagiert anständig auf alle möglichen Fehlerzustände. Es kann reconnect. Es kann mit Servern umgehen, die sich nicht an Standards halten. Es geht selbst sehr pingelig mit Standards um. Du kannst beliebige Header setzen und auch im Result alle Header auslesen. Das Codebeispiel ist nur die einfachste Möglichkeit, einen HTTP-Request auszuführen. Will ich mehr, wird es natürlich ein wenig komplizierter. Das liegt in der Natur der Sache. Aber auch diese Interfaces sind keine Rocket-Science. Die Funktionalität ist also nicht, wie Du es annimmst "stark eingeschränkt".

    Alle Möglichkeiten aufzulisten würde hier zu weit gehen. Ach ja - gzip-Komprimierung kann er tatsächlich nicht. Das ist dann tatsächlich eine Einschränkung.

    Es gibt außerdem noch higher level interfaces wie z.B. xmlrpc, welches auch asyncron arbeiten kann. So kann ich in einer Eventloop mehrere xmlrpc-Request parallel ausführen oder in der gleichen Event loop noch einen (oder mehrere) xmlrpc-Server laufen lassen.

    Ach ja, und noch was: was ist an getaddrinfo Kaputt? Du schreibst so, als wüsste es jeder. Und was sind "Namenstabellen"?



  • tntnet schrieb:

    Eine Beleidigung nach der anderen.

    Nee, du weißt einfach nur nicht, was eine Beleidigung ist. Jemandem zu sagen, er halluziniert, ist keine Beleidigung - das ist normales, menschliches Verhalten. Ironischerweise sind gerade Leute mit einem großen Ego nicht in der Lage, dies zu akzeptieren - der Stolz verbietet es.

    "Hey, du riechst aus dem Mund!" - ist das eine Beleidigung? Nein, das passiert bei Menschen nun mal. Genau wie Halluzinationen. Jemand hat sich heute schon lächerlich gemacht, indem er mir unterstellt hat, dass Geisteskrankheit und Halluzination das gleiche sind. Geisteskrankheit bestimmt, wie du Sachen interpretiert. Halluzinationen beeinflussen, was für Sachen du siehst. Erste bestimmen die Verarbeitung, letztere die Eingabe. Und das gemeine ist, dass du es nicht mal sehen kannst. Die Chance ist ziemlich groß, dass du dir jetzt "Was für ein Unsinn!" sagen wirst - und dass du direkt in die Halluzination reinfällst. Für dich komplett logisch, aber von außen fragt man sich halt, was das soll.

    tntnet schrieb:

    Du fängst gleich damit an, dem Originalposter zu fragen, ob er Muttersprachler ist. Damit wirfst Du ihm vor, er würde schlechtes Deutsch schreiben.

    Ist das nicht evident? Oder soll das wieder eine Beleidigung sein?

    Auch hier wieder Halluzination. Du siehst etwas, weil dein Ego es sehen will. Er verwendet einen Begriff, der da nicht reingehört. Von dem er nicht weiß, was er bedeutet. Warum tut er das nicht? Ist er Muttersprachler oder nicht? Soll ich Nachsicht haben oder nicht?

    Meinen Onkel hat man mal gefragt, ob er überhaupt der deutschen Sprache mächtig ist. Er ist ebenfalls Muttersprachler. In der Frage ist keine Beleidigung drin, sondern höchstens die Aufforderung, dass man deutlicheres Deutsch sprechen könnte. Da das Ego aber einen halluzinieren lässt, ignoriert man diese Aufforderung, und interpretiert die Ehrverletzung als Beleidigung.

    Ist es das, worum es dir geht? Dass ich für dich Nichtmuttersprachler geschliffenes Deutsch schreiben soll? Das kann ich ja machen. Aber dann hör auf, zu behaupten, dass das völlig falsches Deutsch sein soll. Ist es nicht. Der Post mit Hauptsatz und Nebensatz ist zwar stilistisch übertrieben, aber dennoch faktisch korrekt. Wenn du es nicht verstehen solltest, dann sag es doch, und dann verwende ich vollständig ausgeschriebene Sätze. Oder wir können direkt in Englisch kommunizieren. Ich habe da keine Ängste.

    tntnet schrieb:

    Das nenne ich Ego-Trip.

    Weißt du, das könnte man annehmen - wenn ich von dir jemals Argumente gehört hätte, die über ein "Du hast aber unrecht!!1!" hinausgehen würden. Ich habe bereits auf Haupt- und Nebensätze verwiesen und erklärt, wieso das Verb im Nebensatz fehlen darf. Wenn das falsch sein sollte, dann widerlege sie bitte.

    Was du mir wohl vorwerfen kannst, ist, dass ich nicht den offiziellen Namen "Satzwertige Ausdrücke" verwendet habe. Aber das ist weit von "in der Hektik unverständlich formuliert" entfernt.

    tntnet schrieb:

    Das ist keine Frage, sondern eine Annahme, dass man keinen eigenen Speicher angeben kann, was Du offensichtlich für unabdingbar hälst.

    1. Hältst.
    2. Habe ich das bereits auch geschrieben:

    dachschaden schrieb:

    Da mache ich mir die Mühe, lade deinen Code runter, schaue ihn mir ein bisschen an und mache Anmerkungen.

    Natürlich sind das Annahmen. Sind sie falsch? Ich habe bisher noch nicht weitergelesen. Was ich sehe, sind die Konstruktoraufrufe der Objekte.

    Unabdingbar ist die Angabe von eigenem Speicher nicht. Es ist lediglich ein Qualitätsmerkmal, welches du selbst in der C-Standardlib findest (dass man also einen Buffer mitgeben kann/soll, in den reingeschrieben wird). Meine persönliche Erfahrung war, dass ich als Anfänger gar nicht verstanden habe, warum man immer Speicher angeben soll. Das soll die Sprache doch für mich machen!!1!

    Erst mit der Zeit ist mir aufgefallen, dass die Leute hinter dem Interface ein paar Sachen wussten, die ich nicht wusste. Z.B. dass Speicherreservierung teuer ist. Dass man mir die Chance geben will, meinen eigenen Speicher anzugeben, weil die Programmierer mich für schlau genug halten, dass ich weiß, was ich tue. Und das ist die Philosophie von C - dass ich weiß, was ich tue. Wenn ich's nicht tue, soll ich eine andere Sprache verwenden. Die Schnittstelle wurde so gebaut, dass ich mündig mit ihr arbeiten kann, anstatt dass ich unmündig davor sitze, weil alles für mich ohne meinen Willen erledigt wird. Ja, es ist im Grunde ein Kampf um die eigene Aufklärung. Ich will einen Default, aber immer die Möglichkeit haben, einzugreifen.´

    Und wenn du diese Möglichkeit nicht bietest, dann aus drei Gründen:

    1. du möchtest bewusst nicht, dass der Programmierer aufgeklärt ist (Friss oder stirb!).
    2. du möchtest dir nicht die Mühe machen.
    3. du erkennst die Problematik nicht.

    Ich unterstelle dir keine Böswilligkeit, deswegen würde ich für 2 und/oder 3 plädieren - aber das Problem wird ja dadurch auch nicht gelöst.

    tntnet schrieb:

    Der Satz "Also so ganz überzeugt bin ich ja nicht ..." ist keine ideale Einleitung sondern eine Herausforderung. Du hoffst, dass ich ein so großes Ego habe, dass ich da drauf springen muss.

    Hoffnung war dabei, aber eher darauf, selbst etwas bei lernen zu können.

    tntnet schrieb:

    Ich reagiere nicht, indem ich mich verzweifelt erkläre, wie man es bei einem Ego-Trip machen würde, sondern lasse es einfach so stehen und akzeptiere das. Also genau das Gegenteil vom Ego-Trip, den Du mir vorwirfst.

    Und hier ist sie wieder, die Halluzination.

    Egos können sich auf mehrere Arten manifestieren. Entweder, indem man sämtliche Kritik nicht an sich heranlässt (was du getan hast - oder zumindest hast du so gewirkt), oder indem man den anderen niedermacht, mit oder ohne Beispiele:

    "Dummkopf. Du hast keine Ahnung, wovon du redest. Schau dir xxx.cpp, Zeile 23 - 42. Da hast du dann de-chunken ohne Kopie! Einen solchen Analphabeten habe ich ja noch nie getroffen."

    Was ich erwartet hätte? Ganz ehrlich?

    "http_state.c. Da werden die Sachen geparst. Studium überlasse ich dir."

    Nix Ego. Keine Herabsetzung. Hier sind die Fakten, bamm, bamm, bamm, keine Zeit für irgendeinen Blödsinn. Nur weil du nicht auf der anderen Seite des Spektrums warst, heißt das nicht, dass du in der Mitte warst.

    tntnet schrieb:

    Du wirfst mir eine schlechte Arbeitseinstellung vor.

    Noch einmal, soll ich von Böswilligkeit ausgehen?

    tntnet schrieb:

    Auch wieder offensichtlich mit dem Ziel, mich zu beleidigen. Das sieht wirklich nicht nach Interesse aus.

    Also ist es dir lieber, das Evil Genius zu sein?

    tntnet schrieb:

    Es reagiert anständig auf alle möglichen Fehlerzustände.

    Was ist "anständig"?

    tntnet schrieb:

    Aber auch diese Interfaces sind keine Rocket-Science. Die Funktionalität ist also nicht, wie Du es annimmst "stark eingeschränkt".

    OK, nehmen wir mal an, dass ich den gleichen Speicher für den temporären HTTP-Request-String und den schlussendlichen Response verwenden möchte, wie ich schon beim Durchgehen der Prozessliste und dem Einladen einer Konfigurationsdatei verwendet habe? In der Regel habe ich bei sowas bereits vier 2-MiB-Pages reserviert, die ich gerne weiterverwenden würde. Und wenn noch mehr Speicher zum Schreiben der Daten verwendet wird, soll sich der Speicher noch weiter erhöhen können.

    Das sind kein konstruierter Fall - das habe ich schon öfter schreiben müssen. Vielleicht habe ich hier nur hohe Standards, aber wenn ich das nicht ohne Verrenkungen machen kann, dann ist das Interface für mich nun mal stark eingeschränkt.

    tntnet schrieb:

    Ach ja, und noch was: was ist an getaddrinfo Kaputt? Du schreibst so, als wüsste es jeder. Und was sind "Namenstabellen"?

    1. Sagen wir mal, ich möchte nur einen, oder zwei, oder drei Hosts maximal haben. Mein naives C-Gehirn sagt mir, dass ich dafür (für das Abspeichern) drei Parameter brauche:

    - den Buffer, in dem die Objekte geschrieben werden.
    - Anzahl an Elemente, die maximal reingeschrieben werden können.
    - Zeiger auf eine Variable, die die Anzahl aller geschriebenen Elemente erhält.

    (den ganzen anderen Quatsch mit den hints und node und so weiter lassen wir mal komplett außer Acht. Den dritten Parameter könnte man in einen In-Out-Parameter verwandeln - sprich, er muss gesetzt sein, und wird dann selbst von der Funktion neu gesetzt, aber das empfand ich immer als hässlich. Da kann man aber drüber streiten).

    So - mit dieser Art der Namensauflösung habe ich einen Funktionsaufruf, und kann selbst entscheiden, was mit dem Speicher passieren soll. Verwende ich ihn wieder? Liegt er nur auf dem Stack rum und wird gleich eh wieder entfernt?
    Durch die Elemente kann ich wie durch ein Array iterieren, und weil die Elemente nebeneinanderliegen, erhalte ich außerdem Cache-Lokalität.

    Oh, aber was ist, wenn es noch ganz viele mehr mögliche Adressen für den Namen gibt?

    Meine "spontane" Lösung dafür ist nicht optimal, aber OK: eine andere Funktion schaut im DNS-Cache nach oder macht noch mal einen Lookup, und dann sind sie auch im Cache. Und dann gibt sie mir die Anzahl der Einträge zurück, die sie gefunden hat.

    Und dann kann ich wieder selbstständig Speicher reservieren und verwalten, anstatt das an eine mir unbekannte Funktion zu delegieren.

    2. Sagen wir mal, ich verwalte zwei HTTP-Objekt - wie in Perl User Agents oder so änlich - und beide haben ein bestimmtes Set von Requestdaten (andere Methode, Header, Version, egal). Sie haben auch eine Reihe von aufgelößten Namen, mitunter sogar noch verbundene Sockets, auf verschiedenen Ports, mit verschiedenen Protokollen.

    Naiv würde ich diese Daten in ein privates Array oder Vektor oder so tun (auch hier kann ich wieder mit dem Speicher rumspielen, aber halten wir's mal einfach).

    Jetzt will ich mit einem User Agent einen Request an einen Host schicken, der bereits bei einem anderen User Agent bekannt ist. Ich weiß sogar, welcher User Agent das ist. Ich kann jetzt manuell zwischen den beiden vermitteln, aber lieber wäre mir, wenn sie ihre Namenstabellen (oder Verbindungslisten, oder wie du sie auch nennen willst) teilen und synchronisieren würden. Dann müsste ich nicht mal mehr einen Round-Trip zum DNS-Cache auf mich nehmen, sondern könnte mich einfach darauf verlassen, dass die User Agents so viel wie möglich wiederverwerten.



  • dachschaden schrieb:

    tntnet schrieb:

    Eine Beleidigung nach der anderen.

    Nee, du weißt einfach nur nicht, was eine Beleidigung ist.

    Warum schlägst du es nicht mal nach und lenkst nicht durch Anderes ab? Weil du ja Wikipedia so magst Beleidigung (Psychologie) (die Argumentation funktioniert im Wesentlichen auch, wenn wir den juristischen Begriff zugrundelegen würden, der ist aber u.U. zu eng gefasst, um als Grundlage sozialer Normen (Netiquette) geeignet zu sein):

    Eine Beleidigung ist eine Aussage oder Handlung eines Senders, die das Ego bzw. den Stolz eines Empfängers mit negativen Emotionen assoziiert – der Kränkung – und somit herabwürdigt.

    Das Erste, was auffallen muss, ist, dass es auf den Wahrheitsgehalt der Aussage nicht ankommt. Das Wie, Warum und Wann (Kontext!) kann erheblich wichtiger sein. Das Beleidigung kann sich auch aus dem, was nicht gesagt aber impliziert wird, ergeben. Auch muss die Beleidigung nicht unbedingt in der Absicht des Senders liegen, sondern kann auf einem Missverständnis beruhen.

    dachschaden schrieb:

    Jemandem zu sagen, er halluziniert, ist keine Beleidigung

    Es kann eine Beleidigung sein. Insbesondere (aber nicht ausschlieslich, s.o.) dann, wenn diese Behauptung nicht durch durch entsprechende Beobachtungen gedeckt sind.

    dachschaden schrieb:

    "Hey, du riechst aus dem Mund!" - ist das eine Beleidigung? Nein, das passiert bei Menschen nun mal.

    Ja, das passiert, und wenn das Arzt sagt oder eine andere Person im Vertraulichen kann das völlig in Ordnung sein. Wenn aber jemand mit dem Megafon durch die Strassen geht und so etwas von sich gibt, sieht die Sache eben ein bisschen anders aus.

    dachschaden schrieb:

    Jemand hat sich heute schon lächerlich gemacht, indem er mir unterstellt hat, dass Geisteskrankheit und Halluzination das gleiche sind.

    Nenn doch ruhig Namen, wenn du meinst, das wäre so gewesen und müsste hier unbedingt nochmal ausgebreitet werden. Aber vielleicht bist du auch selbst gar nicht davon überzeugt, brauchst es um dein Ego zu streicheln, möchtest aber nicht, dass sich jemand die Mühe macht, und nachschaut, ob das tatsächlich gesagt wurde.

    Falls das zu schwer war, nehme ich es nochmal für dich auseinander:
    Jemandem hier in einer Antwort - ohne erhebliche Evidenz in dieser Hinsicht - zu unterstellen, er würde halluzinieren, muss beleidigend wirken. Denn die bloße Äußerung impliziert, dass diese Evidenz in dessen vorheriger Aussage zu finden ist. Diese vorherige Aussage ist aber nicht das direkte Resultat der Sinneswahrnehmungen des Authors, sondern ein Produkt seine Geistes, und weil ja das Halluzinieren des Authors angeblich so offensichtlich ist, kann es um dessen Geistesverfassung nicht so gut gestellt sein, schliesslich bedeutet das sinnliche Wahrnehmen von Dingen, die nicht existieren, nicht zwingend, dass man sich dieser Täuschung nicht rational bewusst werden kann.
    Nun ist halluzinieren ein Wort mit einer recht klar umrissenen Bedeutung, die auf ein bestimmtes klinisches Erscheinigungbild verweist. Das bedeutet umgekehrt, dass die Verwendung eine starke Abwertung bedeutet in einem Kontext wie etwa diesem Forum, in dem nur ein sehr oberflächlicher Kontakt - und somit keine gesicherte Diagnose - möglich ist. Dabei gibt es ja durchaus Synonyme, wie etwa irren oder täuschen, die diese extreme Abwertung nicht enthalten. Da du dich trotzdem auf diese Vokabel festlegst (mangelnde Sprachkenntnis scheint ja nicht das Problem zu sein), schlussfolgere ich, dass die Beleidigung tatsächlich auch bewusst und gewollt ist.

    Nebenbei bemerkt war mein vorheriger Beitrag, auf den der Halluzinationsvorwurf erfolgt, primär ein Werturteil und damit (mangels absoluten Wahrheitsgehaltes, da abhängig von Wertmaßstäben) nicht mal abstrakt geeignet, Halluzinationen zu belegen. Es sei denn, du bist tatsächlich der Ansicht, dein Verhalten könnte unter keinen Umständen oder Maßstäben kritikwürdig sein. In diesem Fall entbehrte der Halluzinationsvorwurf nicht einer gewissen Ironie.



  • SeppJ warum greifst du hier komischerweise nicht ein?



  • camper schrieb:

    ...

    Danke. Mehr sage ich dazu nicht mehr.

    Und jetzt zum Thema. Ich gehe mal weiterhin davon aus, dass die Verarbeitung von HTTP-Requests interessant ist.

    Erst mal: der Parser ist in der Datei src/http/parser.cpp zu finden.

    Dieses Vorgeben von Speicher halte ich nicht für die richtige Lösung. In aller Regel benötige ich die Daten, die vom Server kommen eben nicht vollständig aufeinanderfolgend im Speicher. Idealerweise schreibe ich einen stateful Parser, welcher Byte für Byte vom Server liest und darauf durch Zustandsübergänge reagiert. Dadurch brauche ich zu keinem Zeitpunkt den vollständigen Request im Speicher zu halten.

    Dafür ist std::streambuf gedacht. Da kann ich Byteweise lesen und wenn ich das nächste Byte brauche, bekomme ich es entweder aus dem Puffer oder der Streambuf holst sich den nächsten Block.

    Im Falle von cxxtools bedeutet das je nach http reply, dass die nächsten Daten entweder direkt vom Socket gelesen werden oder dass noch ein chunkedreader (src/http/chunkedreader.cpp) noch dazwischen ist, der eben genau so arbeitet.

    So kann sich beispielsweise der xmlrpc client in cxxtools ganz darauf konzentrieren, den xmlrpc Request zu parsen und braucht sich nicht darum zu kümmern, dass die Daten möglicherweise nicht am Stück kommen.

    Oder will ich den Reply body auf std::cout ausgeben, ist das ok, wenn ich immer Stückchenweise lese und auf cout ausgebe. Das ist nicht so schwer und kommt vollständig mit kleinen Puffern aus ohne dass zwischendurch Allokationen statt finden.

    Ich habe jetzt verstanden, dass Du (Dachschaden, keine Beleidigung 😃 ) getaddrinfo für unglücklich hälst. Ja im prinzip ist immer das Problem, dass es kein asyncrones Interface to getaddrinfo gibt. Ich glaube, dass an dieser Stelle cachelokalität gar nicht so ins Gewicht fällt, da hier andere Dinge deutlich teuerer sind.

    Im Falle von cxxtools gibt es eine Trennung zwischen client und request. Idealerweise habe ich ein Client-Objekt, welches ich länger halte. Dadurch wird der Verbindungsaufbau inklusive Namensauflösung nur ein mal gemacht. Die Verbindung wird dann für mehrere Request wieder verwendet.

    Du hast auch noch erwähnt, dass chunked encoding schlecht ist, weil man dadurch kein sendfile verwenden kann. Das schöne ist, dass der Server entscheiden kann, was für den Anwendungsfall geeignet ist. Liegen die Daten im Dateisystem, kann einfach ein Content-Length gesendet werden und dann mit sendfile die Daten. Werden die Daten so nach und nach produziert, kann der Server sich dagegen für chunked encoding entscheiden, so dass er am Anfang nicht wissen muss, wie viele Daten noch kommen.

    Du wolltest noch wissen, was es in cxxtools bedeutet, "anständig" auf Fehler zu reagieren. cxxtools wirft im Falle von Fehlern exceptions. Ich könnte jetzt noch darüber schreiben, wie praktisch Exceptions sind und wie elegant man damit robuste Programme schreiben kann, aber darüber wurde schon so viel geschrieben.

    Und noch was @Blockade (wieder keine Beleidigung sondern der Originalposter 🙂 ): Auf Content-Length kann man sich doch verlassen. Das gehört zum Protokoll. Wenn der Server weniger Daten schickt, dann ist der Reply noch nicht vollständig. Wird dann der Socket geschlossen, dann ist das eben ein Fehler. Schickt er mehr, dann gehören die folgenden Daten eben nicht zum reply sondern sind eventuell schon der nächste reply wenn ich mehrere Requests gleichzeitig geschickt habe.


Anmelden zum Antworten