Hallo,
ich versuche mit den Befehl send() 1600 Bytes über das Netzwerk zu
senden. Wireshark sagt mir jedoch, dass nur 140Bytes gesendet werden.
Die Funktion send gibt jedoch 1600 zurück. Sende ich weniger als 1460
Bytes werden sie auch gesendet. Habt ihr eine Ahnung woran das liegen
kann?
Hier die Initialsierung des Servers:
1
intbuild_sock(unsignedshortServPort){
2
intservSock;/* Socket descriptor for server */
3
intclntSock;/* Socket descriptor for client */
4
structsockaddr_inServAddr;/* Local address */
5
structsockaddr_inClntAddr;/* Client address */
6
unsignedintclntLen;/* Length of client address data structure */
Und wie liest du auf der Serverseite?
Wenn die Nachricht segmentiert wird, musst du nicht nur einmal lesen,
sondern mehrfach, bis alle 1600 Byte da sind.
Es gibt keine Garantie, daß 1x senden auch nur zu 1x Lesen führt...
Sendest Du TCP/IP oder UDP? Pakete über 1500 irgendwas bytes werden vom
Stack zerstückelt. Du hast doche einen Stack, oder?
Nimmst Du UDP, kann Wireshark die Segmente wieder zusammensetzen. Da
entsteht unten ein Karteireiter reassembled-udp (oder so ähnlich).
Nimmst Du TCP/IP, kann Wireshark das scheinbar nicht, und Du siehst zwei
Pakete hintereinander....
Tobi schrieb:> Das Problem ist, dass ich unter Wireshark keine zwei Pakete sehe, die> ich erwarte. Es wird nur eins mit 140Byte nutzdaten gesendet.
Und die Nutzdaten sind auch von deinem gesendeten Paket oder was
anderes. Falls es von deinem Paket ist, kannst Du sicher sagen ob es der
Anfang oder Ende ist.
Tobi schrieb:> ich versuche mit den Befehl send() 1600 Bytes über das Netzwerk zu> senden. Wireshark sagt mir jedoch, dass nur 140Bytes gesendet werden.> Die Funktion send gibt jedoch 1600 zurück.
Die offensichtliche Frage ist dann doch, was beim Empfänger ankommt.
Sind alle 1600 Bytes da und auch korrekt? Oder kommt da tatsächlich
nichts an?
Tobi schrieb:> send(clntSock,data, 1600 ,0);
Und warum wertest du den Return Code von send nicht aus? Da stehen die
Anzahl gesendeter Bytes drin.
Eventuell ist dein TCP Stack so konfiguriert, daß das send direkt
zurückkommt und nur die Anzahl Bytes die sofort gesendet werden konnten
ausgibt.
Beim senden und empfangen IMMER die returncodes auswerten. Ich hatte mal
einen Fehler da wolle ich nur 2 Bytes empfangen und ein einem von 100000
Fällen wurde beim ersten receive nur eines der beiden Bytes empfangen
und ich musste ein 2. absetzen.
Ausserdem sendest du ein int einfach so, ohne auf NetByteOrder zu
konvertieren, das geht dann schief, wenn Sender und Empfänger
unterschiedliches Byte ordering haben.
Udo Schmitt schrieb:> Beim senden und empfangen IMMER die returncodes auswerten.
Ist zwar schon eine Weile her, dass ich das letzt mal auf dieser Ebene
unterwegs war, aber müsste man das nicht so programmieren
1
...
2
bytes=(uint8_t*)data;
3
bytes_len=1600*sizeof(unsignedshort);
4
do
5
{
6
bytes_sent=send(clntSock,bytes,bytes_len,0);
7
bytes+=bytes_sent;
8
bytes_len-=bytes_sent;
9
}while(bytes_len>0||bytes_sent!=-1)
10
...
d.h. in einer Schleife solange sukzessive immer wieder den nächsten Teil
auf den Weg bringen, bis alles draussen ist.
Der größte Fehler in der ganzen Sockerprogrammierung besteht IMHO in der
Annahme, dass mit einem send Aufruf die kompletten Daten vom Stack
übernommen werden bzw. auf der Empfangsseite, dass man die auch wieder
zusammenhängend und in einem Stück aus dem recv rausbekommt. Man muss
immer damit rechnen, dass einem der TCP/IP Stack die Daten zerstückelt
und auf der Gegenstelle zwar in der richtigen Reihenfolge, aber nicht
notwendigerweise in derselben Länge wieder zusammensetzt.
>Ausserdem sendest du ein int einfach so, ohne auf NetByteOrder zu
Gibt es dazu irgendeine Beschreibung?
Ich führe dieselbe Diskussion hier in der FIrma seit Jahren. Hier werden
auch einfach Datentypen grösser ein Byte mit memcopy in den Sendepuffer
kopiert. Probleme treten dann immer auf, wenn sich die Länge dadurch
ändert, der Compiler andere Alignment/Füllbytes nutzt, etc..
Ist das irgendwo beschrieben, das es quasi empfohlen wird, zum Versenden
eigener Daten vorher also ein Byte-array selbst aufzubauen?
Matthias Lipinsky schrieb:> Hier werden> auch einfach Datentypen grösser ein Byte mit memcopy in den Sendepuffer> kopiert. Probleme treten dann immer auf, wenn sich die Länge dadurch> ändert, der Compiler andere Alignment/Füllbytes nutzt, etc..
das passiert aber nur bei Structs. Bei einem int kann das nicht
passieren. Auch nicht bei einem Array von ints.
Dort sehen ich keine Problem bei senden, und mache es selber so.
>das passiert aber nur bei Structs. Bei einem int kann das nicht>passieren. Auch nicht bei einem Array von ints.
Ist richtig. Meine Frage hat nicht direkt mit dem Problem des TO zutun.
Passte nur auf den Kommentar. Hier bei mir geht es um structs, wo alle
möglichen Datentypen intern verwendet sind...
Matthias Lipinsky schrieb:>>das passiert aber nur bei Structs. Bei einem int kann das nicht>>passieren. Auch nicht bei einem Array von ints.>> Ist richtig. Meine Frage hat nicht direkt mit dem Problem des TO zutun.> Passte nur auf den Kommentar. Hier bei mir geht es um structs, wo alle> möglichen Datentypen intern verwendet sind...
"Empfohlen" ist ein großes Wort. Letzten Endes ist das ja auch nichts
anderes als das immer gleiche Problem, dass man bei rein binärer
Datenübertragung (egal ob das jetzt per UART oder per Netzwerk ist, oder
ob man auf ein File schreibt) sich immer den Nachteil einhandelt, auf
genau diese binäre Repräsentierung festgenagelt zu sein. Einen struct
als ganzes auf ein File zu schreiben, geht zwar mit einem write
wunderbar einfach, aber wehe der struct verändert sich. Wohl dem, der
sich dann wenigstens Versionstags ins File eingebaut hat um wenigstens
den Ansatz einer Aufwärtskompatibilität erreichen zu können.
Meiner Meinung nach ist es ein Zeichen von mangelnder Erfahrung bzw. dem
noch nie in der Situation gewesen sein, ein Fileformat
(aufwärts-)kompatibel erweitern zu müssen, wenn einfach her gegangen
wird und die internen Daten naiv binär und ohne zusätzliche
Verwaltungsinfo in der internen Repräsentierung über Schnittstellen
rausgegeben werden. Egal ob das jetzt File oder Netzwerk ist. Die
Probleme sind da wie dort die gleichen.
Aber Link in dem Sinne hab ich auch keinen. Das scheint mir irgendwie
Basiswissen zu sein, dass jeder hat. Spätestens wenn man dann vor dem
Trümmerhaufen steht und ihn nicht mehr entwirren kann, fällt es einem
wie Schuppen von den Augen, warum alle eben nicht einfach nur naiv binär
die interne Repräsentierung rausgeben, auch wenn das momentan
verführerisch einfach ist und auch momentan funktioniert. Aber als SW
Entwickler muss man auch in die Zukunft denken und was wäre wenn
Spielchen spielen. Denn spätestens die Kunden sagen einem dann schon,
was sie davon halten, dass ihre vorhandenen Daten mit der nächsten
Programmversion unbrauchbar sind.
Ich löse das immer so, das ich mir ein Bytearray selbst baue und
festlege, welcher Arrayindex welches (HI/LO)Byte von welchem Member
welcher Struct aufnimmt:
1
buf[0]=(uint8_t)(IDENT);
2
buf[1]=(uint8_t)(IDENT>>8);
3
buf[2]=(uint8_t)(LEN);
4
buf[3]=(uint8_t)(LEN>>8);
5
buf[4]=(uint8_t)...
6
buf[5]=(uint8_t)...
7
buf[6]=(uint8_t)(MyStruct2.Var2);
8
buf[7]=(uint8_t)(MyStruct2.Var2>>8);
9
...
Das IDENT ist bei mir ein Code, anhand dessen ich per CASE die Meldung
und deren Inhalt erkennen kann. LEN ist die Länge der Gesamten Meldung.
Damit kann ich bei unbekannten IDENT immernoch drüberspringen und diesen
Teil ignorieren...
Ist das eher schlecht, oder wie seht ihr das? Zumindest bin ich
auf/abwärtskompatibel, kann Erweiterungen einfach einbauen durch Vergabe
neuer IDENT-s...
Matthias Lipinsky schrieb:> Ist das eher schlecht, oder wie seht ihr das? Zumindest bin ich> auf/abwärtskompatibel, kann Erweiterungen einfach einbauen durch Vergabe> neuer IDENT-s...
kommst darauf an was man erreichen will. Wenn man ein Cluster für HPC
betreibt. Kostet die zusätzliche Umwandlung Zeit und damit Geld. Das so
ein Cluster überall mit der gleichen Software läuft bringt es auch keine
Vorteile.
Wenn man dagegen Daten zwischen verschiedenen Plattformen und
Programmversionen austauscht macht das schon sinn.
>Wenn man dagegen Daten zwischen verschiedenen Plattformen und>Programmversionen austauscht macht das schon sinn.
Das ist hier eigentlich Ziel. Wenns immer derselbe Prozessor und
Compiler ist, ist das egal. Aber hier gibt es jetzt verschiedene
SPS-Hersteller, Intel, ARM, PC/SPS....
Und dann will ich eigentlich die Kontrolle über die Bedeutung der
Datenbytes auf dem Netzwerkmedium haben und nicht der Compiler mit
Füllbytes und Alignment...
Karl Heinz schrieb:> d.h. in einer Schleife solange sukzessive immer wieder den nächsten Teil> auf den Weg bringen, bis alles draussen ist.
Genau. Zumindest in erster Näherung den return Code AUSWERTEN!. Daß beim
Senden nicht alles gesendet wird ist allerdings etwas ungewöhnlich. Aber
es gibt eine Million TCP Stacks...
Karl Heinz schrieb:> Man muss> immer damit rechnen, dass einem der TCP/IP Stack die Daten zerstückelt> und auf der Gegenstelle zwar in der richtigen Reihenfolge, aber nicht> notwendigerweise in derselben Länge wieder zusammensetzt.
Richtig, wie gesagt, wir haben mal wochenlang einen Phantomfehler
gesucht, der nur beim Kunden selten auftrat. Ursache war daß eine Länge
(2 Bytes und ein Datenpaket gesendet wurde, und bei der Länge nicht
geprüft wurde ob auch 2 Bytes empfangen worden waren. Bei den Daten
dahinter wurde es korrek tmit der Schleife gemacht. Aber in einem von
100000 Fällen kam beim ersten Aufruf nur ein Byte an :-(
Matthias Lipinsky schrieb:> Probleme treten dann immer auf, wenn sich die Länge dadurch> ändert, der Compiler andere Alignment/Füllbytes nutzt, etc..
Die einzig saubere Lösung ist hier für jedes komplexere Objekt (Struct)
eine saubere serialize() und deserialize() Funktion zu schreiben. Hat
den Vorteil damit dann auch die Daten sauber in jeden beliebigen Stream
(z.B.) Datei schreiben und auch wieder lesen zu können. Und wenn man für
die Basis-Datentypen dann noch ein festes Byte Order definiert sogar
über Rechner/Betriebssystemgrenzen hinweg.
Matthias Lipinsky schrieb:> Und dann will ich eigentlich die Kontrolle über die Bedeutung der> Datenbytes auf dem Netzwerkmedium haben und nicht der Compiler mit> Füllbytes und Alignment...
denn legt man eh eine Protokoll fest. Und wie man es erreicht das man
die Daten richtig rausschreibt kann man sich selber überlegen.
Man kann z.b. auch die Struktur "packed" anlegen. Dann kann man es
einfach raussenden. Dazu kann man noch eine Check in der Form
Sizeof(xx) != DATA_SIZE einbauen und schon kann man ohne jedes Byte
anzufassen die Daten versenden.
Peter II schrieb:> und schon kann man ohne jedes Byte> anzufassen die Daten versenden.
Geht spätestens schief, wenn man von einer Low Endian auf eine Big
Endian Maschine sendet.
>Die einzig saubere Lösung ist hier für jedes komplexere Objekt (Struct)>eine saubere serialize() und deserialize() Funktion zu schreiben.
Das habe ich ja prinzipiell durch das händische Einsortieren gemacht.
>Hat>den Vorteil damit dann auch die Daten sauber in jeden beliebigen Stream>(z.B.) Datei schreiben und auch wieder lesen zu können. Und wenn man für>die Basis-Datentypen dann noch ein festes Byte Order definiert sogar>über Rechner/Betriebssystemgrenzen hinweg.
Das will ich erreichen. Gibt es dazu irgendwas "schriftliches"? Eine
Empfehlung etc. Was nicht von mir ist und ich hier mal rumzeigen kann.
SO nach dem Motto, so wirds richtig gemacht...
Udo Schmitt schrieb:> Geht spätestens schief, wenn man von einer Low Endian auf eine Big> Endian Maschine sendet.
richtig, aber auch dafür kann man einen Check einbauen. Wenn zu 99.9%
feststeht das diese Software niemals seine Plattform wechselt ist das
durchaus vertretbar.
Man könnte auch alles als XML übertragen, dann ist sogar das ausdrucken
und einscannen möglich ...
Matthias Lipinsky schrieb:> Das will ich erreichen. Gibt es dazu irgendwas "schriftliches"? Eine> Empfehlung etc. Was nicht von mir ist und ich hier mal rumzeigen kann.> SO nach dem Motto, so wirds richtig gemacht...
es gibt keine richtig! Es muss seinen zweck erfüllen, und dafür gibt es
verschiede Wege.
Man legt ein Protokoll fest und jeder Entwickler hat dafür zu sorgen,
das die Daten in diesem Protokoll übertragen werden, wie er das macht
sollte ihm überlassen sein.
Matthias Lipinsky schrieb:> Das will ich erreichen. Gibt es dazu irgendwas "schriftliches"? Eine> Empfehlung etc. Was nicht von mir ist und ich hier mal rumzeigen kann.
In "modernen" Sprachen wie Java und c# gibt es dafür die serialize und
deserialize.
Man wandelt ein Objekt/Struct explizit in ein Byte Array und wieder
zurück und ist damit völlig unabhängig von der Plattform.
Auf die Schnelle:
http://msdn.microsoft.com/en-us/library/ms233843.aspxPeter II schrieb:> Wenn zu 99.9%> feststeht das diese Software niemals seine Plattform wechselt ist das> durchaus vertretbar.
Genau dann und nur dann. Sobald aber 2 Plattformen/Betriebssysteme ins
Spiel kommen sollte man es richtig machen.
Peter II schrieb:> Man könnte auch alles als XML übertragen
Genau da passiert das implizit. Die Objekte müssen dazu ein
serialize/deserialize Interface haben.
Udo Schmitt schrieb:> In "modernen" Sprachen wie Java und c# gibt es dafür die serialize und> deserialize.> Man wandelt ein Objekt/Struct explizit in ein Byte Array und wieder> zurück und ist damit völlig unabhängig von der Plattform.
aber nur wenn auf beiden Seiten die Objekte gleich sein. Aber was ist
wenn bei einer Version ein neues Feld dazu kommt?
Ist denn von der Sprache festgelegt, das sich im nächsten Release das
Format nicht ändert? Und was ist wenn eine Seite Java und die andere
Seite .net ist?
Das ist auch nicht viel besser als eine Struct einfach rauszuschreiben.
@Matthias:
Allgemeinere Beschreibung des Konzepts:
http://en.wikipedia.org/wiki/SerializationPeter II schrieb:> aber nur wenn auf beiden Seiten die Objekte gleich sein. Aber was ist> wenn bei einer Version ein neues Feld dazu kommt?> ...> Das ist auch nicht viel besser als eine Struct einfach rauszuschreiben.
Dann muss man das in einer höheren Ebene abfangen. Aber zu sagen Ich
kann ein geändertes Objekt nicht erkennen, also scheiss ich drauf Byte
Ordering und PaddingBytes zu berücksichtigen ist ja wohl völlig daneben.
Wenn du geänderte Strukturen auch noch erkennen willst dann musst du
halt den nächsten Schritt gehen und das alles in eine Semantik setzen,
so wie es zum Beispiel modernere Webservice Protokolle bieten.
Da kann man sogar Strukturen erweitern und ältere Clients/Server können
dann trotzdem noch funktionieren, solange die Erweiterungen optional für
die Funktion sind.
Peter II schrieb:> Und was ist wenn eine Seite Java und die andere Seite .net ist?
Das ist völlig transparent wenn du es richtig machst. Lese dich mal in
Webservice mit WSDL ein (z.B. mit SOAP)
Machen wir hier sogar mit Finanzsoftware bei Banken.
>und das alles in eine Semantik setzen,
Schon, aber ich arbeite hier nicht im Betriebsystem Windowa oä mit
(quasi) unbegrenzten Resourcen, wo ich zur Übertragung eines Dwords
(4Byte) etxra noch 100Bytes als Stringoverhead ergänzen möchte...
Deshalb hab ich mir das mit den IDENTS und der LEN ausgedacht... Es
funktioniert auch, nur andere memcopy-Schnittstellen will keiner
anfassen...
Das Problem habe ich jetzt gelöst. Jetzt ärgert mich nur noch der FPGA.
In meinen Fall bleibt das System immer gleich. Das System ist altera
FPGA mit integrierten arm Prozessor auf den ein Linux läuft
Udo Schmitt schrieb:> Das ist völlig transparent wenn du es richtig machst. Lese dich mal in> Webservice mit WSDL ein (z.B. mit SOAP)> Machen wir hier sogar mit Finanzsoftware bei Banken.
das ist doch XML. Und Rate mal warum es sich nicht als Netzwerkprotokoll
durchsetzt. Es ist einfach nicht effizient genug.
Das hat nichts mit der Serialisierung von Objekten in verschiedenen
Sprachen zu tun. XML ist eine Form der Serialisierung, es gibt aber auch
noch andere die nicht zwingend portable sind.
Matthias Lipinsky schrieb:>>und das alles in eine Semantik setzen,>> Schon, aber ich arbeite hier nicht im Betriebsystem Windowa oä mit> (quasi) unbegrenzten Resourcen,
Sorry, das war für PeterII der sich mokiert hat, daß man bei der
Änderung einer Struktur!!! die alten Daten nicht mehr korrekt eingelesen
bekommt.
Du brauchst ja nicht, daß ein Client der Version 2.x noch mit einem
Server der Version 4.x und geänderter Datenstruktur noch kommunizieren
muss.
Es ging ja rein um eine sauberes Art und Weise komplexere
Datenstrukturen zu senden/empfangen bzw schreiben und wieder zu lesen.
Matthias Lipinsky schrieb:>>Das Problem habe ich jetzt gelöst.>> Und wie? Lass uns doch an der Lösung teilhaben
Da bin ich auch mal gespannt, nachem ich auf meine Frage nie eine
Antwort bekommen habe...
Peter II schrieb:> das ist doch XML.
Es wird hier (SOAP) XML benutzt, wobei auch das nicht zwingend ist. Du
solltest mal etwas aus der MS und Windows Ecke rauskommen und über den
Tellerrand schauen :-)
Peter II schrieb:> Und Rate mal warum es sich nicht als Netzwerkprotokoll durchsetzt.
In vielen (höheren) Protokollen wird es benutzt.
Peter II schrieb:> Es ist einfach nicht effizient genug.
Von höchster Effizienz war in dem ganzen Thread bis jetzt nicht die
Rede.
Und bei Netzwerken ist Effizienz sowieso eine kniffelige Sache, bei der
du an 100 Stellen Fehler machen kannst.
Ausserdem war Webservice und SOAP nur ein Beispiel für Semantik für
deinen plötzlich hingeworfener Einwand eine geänderte Struktur nicht
mehr lesen zu können (die mit deiner Methode genausowenig verarbeitet
werden kann!)
Peter II schrieb:> XML ist eine Form der Serialisierung
Serialisierung hat erst mal nichts mit XML zu tun, das ist rein die
Übertragung einer Struktur in ein Byte Stream und zurück
(deserialisierung).
Das hatte ich auch nirgends geschrieben!
Udo Schmitt schrieb:> Es wird hier (SOAP) XML benutzt, wobei auch das nicht zwingend ist. Du> solltest mal etwas aus der MS und Windows Ecke rauskommen und über den> Tellerrand schauen :-)
was hat das mit Windows zu tun? Oder kann Linux noch nicht mal XML?
> Ausserdem war Webservice und SOAP nur ein Beispiel für Semantik für> deinen plötzlich hingeworfener Einwand eine geänderte Struktur nicht> mehr lesen zu können (die mit deiner Methode genausowenig verarbeitet> werden kann!)
irgendwie haben wir reden wir aneinander vorbei. Ich habe gesagt man
legt einfach das Protokoll fest (welches Byte bedeutet was...). Wie man
diese Daten rausschreibt, kann man dann selber entscheiden. Und wenn man
sie in einen passenden Struct steckt und das einfach rauschreibt oder
sie vorher in ein bytearray kopiert ist dabei egal.
Und im Protokoll gibt es eine Versionsnummer, damit kommt man auch mit
Protokolländerungen klar.