[TCP/IP] Zwischen verschiedenen sends unterscheiden



  • Hi,

    Ich versende per TCP/IP mit send() vom Client eine Zahl an den Server die für einen bestimmten Command steht. Danach sende ich dem Command entsprechende Parameter. Ich schicke also mit dem ersten send eine '6' für 'ändere die Lautstärke' und mit einem 2ten send die Lautstärke (als Zahl) selbst.
    Auf der Server Seite ist befindet sich eine unendliche Schleife in der mit recv() auf einen Command gewartet wird. Wird einer empfangen, wird dem Command entsprechend ein weiteres recv() aufgerufen um die Parameter des Commands zu empfangen um sie anschließend zu verarbeiten.

    Nun habe ich aber das Problem dass wenn Commands schnell hintereinander geschickt werden, die recv()-Schleife die ganzen sends in einem einzigen recv() empfängt, und mir so die Unterscheidung zwischen Command und Parameter unmöglich macht.

    Jetzt die Frage: Wie ist der korrekte weg diese Command/Parameter Sache zu machen, oder überhaupt, Daten zu empfangen und zu verarbeiten? Ein Trennzeichen mitschicken?

    Vielen Dank,
    Luke



  • Schick ein Trennzeichen mit, was sonst?

    btw. was hat das mit ANSI C zu tun? Nicht nur das ANSI C kein TCP/IP kennt, es handelt sich ja um ein Protokoll-Problem



  • machs als paket

    paket haet laenge, command, parameter.

    du empfaengst immer ganze pakete. hast du eins zusammen, wirds verarbeitet.
    -> laenge empfangen. rest empfangen. paket fertig.

    hast du mehrere pakete im puffer, arbeitest du die eben nacheinander ab.

    hast du kein ganzes im puffer, nochmal recv()

    den prozess kannste "optimieren", indem du immer viel empfaengst und das in den puffer laedst.
    nach dem empfangen guckst du, ob im puffer ein ganzes paket liegt.
    nein? nochmal recv()
    ja? paket aus puffer entfernen und weiterleiten. restliche daten im puffer natuerlich nachrutschen lassen (ringpufferartiges bevorzugt)



  • Meinst du mit Paket die Länge des Commands & Parameter am Anfang mitschicken, oder gibt es da schon was?



  • Luke-2 schrieb:

    Nun habe ich aber das Problem dass wenn Commands schnell hintereinander geschickt werden, die recv()-Schleife die ganzen sends in einem einzigen recv() empfängt, und mir so die Unterscheidung zwischen Command und Parameter unmöglich macht.

    du kannst ja bei 'recv' angeben, wieviele bytes du haben willst. mach' den wert einfach auf '1' und schon liest du byteweise. das ist zwar gewschwindigkeitsmässig nicht besonders günstig, aber dürfte dein problem lösen.



  • @Luke-2
    Welches Betriebssystem? (Ich hätte jetzt auf Linux/Unix getippt)



  • vista schrieb:

    das ist zwar gewschwindigkeitsmässig nicht besonders günstig

    Ich will's da leiber bei Geschwindigkeit halten... .

    AJ schrieb:

    @Luke-2
    Welches Betriebssystem? (Ich hätte jetzt auf Linux/Unix getippt)

    So wie ich's beschrieben hab ist der Client Windows und der Server Linux (genauergenommen ne PSP), allerdings läuft auf der PSP auch noch ein Client und auf der Windows-Maschiene ein Server bei dem ich wahrscheinlich das gleiche Problem haben werde. Es wird aber immer ne Linux-Windows Connection werden, da das eine (wie gesagt) ne PSP ist, und das andere Winamp.



  • Dieser Thread wurde von Moderator/in TactX aus dem Forum ANSI C in das Forum Rund um die Programmierung verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Du musst lediglich verstehen, dass TCP ein Bytestrom ist. Analog einer Datei beispielsweise, dort kannst du ja auch später nicht mehr erkennen, wie genau die Bytes da reingekommen sind.
    Dass du manchmal mit recv genau das empfängst was du auch mit einem send abgeschickt hast ist ein Nebeneffekt der Tatsache, dass TCP auf einem paketbasierten Protokoll aufsetzt, aber nichts, auf das man sich verlassen kann.



  • Ok, das heißt wohl dass ich zuerst die Größe eines Commands mit Parameter mitschicken muss, oder?

    Und noch eine essentielle Frage: Ist es garantiert dass die Bytes in der Reihenfolge ankommen in der sie losgeschickt wurden? So weit ich weiß ist das bei TCP/IP so vorgesehen, aber da bin ich mir jetzt auch nicht mehr sicher... .



  • Luke-2 schrieb:

    Ok, das heißt wohl dass ich zuerst die Größe eines Commands mit Parameter mitschicken muss, oder?

    nein, nicht unbedingt...

    Luke-2 schrieb:

    Und noch eine essentielle Frage: Ist es garantiert dass die Bytes in der Reihenfolge ankommen in der sie losgeschickt wurden? So weit ich weiß ist das bei TCP/IP so vorgesehen, aber da bin ich mir jetzt auch nicht mehr sicher... .

    ja, wie Bashar schon sagte verhält sich eine TCP-verbindung wie ein serieller bytestrom (RS232, datei, tastatur, etc.). die daten kommen immer in der reihenfolge an, in der sie abgeschickt wurden und es gibt auch keine bitfehler o.ä.
    nur das zeitverhalten ändert sich.



  • vista schrieb:

    ja, wie Bashar schon sagte verhält sich eine TCP-verbindung wie ein serieller bytestrom (RS232, datei, tastatur, etc.). die daten kommen immer in der reihenfolge an, in der sie abgeschickt wurden und es gibt auch keine bitfehler o.ä.
    nur das zeitverhalten ändert sich.

    *erleichterung* 🙂

    vista schrieb:

    nein, nicht unbedingt...

    Was heißt das? Was wäre die bessere Alternative?



  • Luke-2 schrieb:

    Was heißt das? Was wäre die bessere Alternative?

    das kommt drauf an.
    sendest du messages definierter länge, dann brauchst du keine zusätzlichen längenangaben.
    sind in diesen messages felder variabler länge, dann brauchst du längenangaben oder trennzeichen.
    sendest du grosse rohdatenmengen und möchtest hin und wieder ein steuerzeichen einfügen, dann wäre vielleicht 'byte stuffing' das richtige.
    ...und wenn man sich so ein protokoll definiert und wenn's auf geschwindigkeit ankommt, sollte man auch noch darauf achten, so wenig wie möglich zu übertragen...
    🙂



  • Ich sende wie gesagt Commands mit Parameter. Die Commands sind im Moment alle nur ein Zeichen lang (vielleicht später noch 2) und die Parameter 1-2 Zeichen, bis auf einen Fall, wo die Parameter theoretisch ins unendliche gehen können, praktisch aber 12000 Zeichen der Extremfall sein wird.

    Ich denke, Längen mitzuschicken wird das beste sein, vor allem da wenn ich ein Trennzeichen benutze, die Suche nach diesem Zeichen rechenintensiver sein könnte, was ich auf der PSP (wo das ganze statt finden wird) nicht gebrauchen kann.

    Vielen Dank.



  • Am einfachsten zu implementieren dürfte wohl ein Trennzeichen sein, also zB "Anweisung Parameter \0" oder "Anweisung Parameter \r\n" (letzteres macht zB HTTP).



  • @Luke-2:
    Wenn du anhand der Commando-Codes die Länge der folgenden Daten bestimmen kannst ("Command 'A' hat immer 2 Byte Daten"), dann musst du natürlich nicht nochmal ein "Längenbyte" vorne mit dranstellen. Wird dann allerdings doof bei Commands mit variabler Datenlänge (Strings, Blobs), da musst du dann je nach Command die Länge irgendwie anders bestimmen.

    Allerdings hat es durchaus einige Vorteile wenn man eine definierte Paketstruktur verwendet, also z.B. Länge (16 Bit), Command-Code (16 Bit), Daten (Variabel). z.B. ist es damit möglich die einzelnen Bytes die du empfängst in Pakete aufzuteilen ohne an der Stelle den Command-Code kennen zu müssen (Layering), oder auch unbekannte Commands (neuer Client, älterer Server) einfach zu überspringen bzw. generisch mit einem "kenn ich nicht" Fehler zu behandeln (ohne gleich die Verbindung abbrechen zu müssen).



  • rüdiger schrieb:

    Am einfachsten zu implementieren dürfte wohl ein Trennzeichen sein, also zB "Anweisung Parameter \0" oder "Anweisung Parameter \r\n" (letzteres macht zB HTTP).

    Ich frage mich halt vor allem was schneller geht (das reine Verarbeiten der Daten, nicht das Senden), längen mitsenden und aufsplitten oder nach dem Trennzeichen suchen (was in meinem Fall wohl ein "\n\n" sein würde, andere Zeichen kommen bei mir in einem gesendetem String schon vor). Ich vermute mal ersteres ist schneller... .

    hustbaer schrieb:

    @Luke-2:
    Wenn du anhand der Commando-Codes die Länge der folgenden Daten bestimmen kannst ("Command 'A' hat immer 2 Byte Daten"), dann musst du natürlich nicht nochmal ein "Längenbyte" vorne mit dranstellen. Wird dann allerdings doof bei Commands mit variabler Datenlänge (Strings, Blobs), da musst du dann je nach Command die Länge irgendwie anders bestimmen.

    Ich weiß bis auf einen Command eigentlich immer die Länge der Parameter. Aber raus aus der Theorie, ganz Praktisch: Ich schreibe hier eine PSP-Fernsteuerung für Winamp. Wenn bei Winamp was passiert, soll das natürlich auf der PSP auch angezeigt werden. Commands (von Winamp zu PSP) werden also Dinge wie Play, Stop, Previous, und Next, sein, aber auch 'Sync Playlist' (die Commands werden als Nummern verschickt). 'Sync Playlist' ist eben der Sonderfall auf den eben die Playlist von Winamp folgt, also ein Haufen Artists und Tracks, die im Muster "Artist - Track \n Nächster Artist - Nächster Track" versendet werden. Als 'Liste Zuende' Zeichen würde ich dann ein einen zweiten \n schicken, wobei ich immer noch glaube dass die Längen mitzuschicken der schnellere Weg ist.



  • Das hört sich nicht gerade nach einer performancekritischen Anwendung an.



  • Bashar schrieb:

    Das hört sich nicht gerade nach einer performancekritischen Anwendung an.

    Nö, aber die PSP hat auch nur 222Mhz im Normalbetrieb und ich habe auch noch vor sie auf 111Mhz runterzutakten um Strom zu sparen



  • ein ganz einfaches protokoll wäre z.b. das: http://en.wikipedia.org/wiki/Type-length-value


Log in to reply