Forum: PC-Programmierung TCP/IP Socket Prgrammierung-Probleme beim Senden/empfangen


von QX (Gast)


Lesenswert?

Hi,

ich habe ein Programm, das über TCP/IP Protokoll eine Zahl schickt und 
der Client empfängt diese.

Nur ist mein Problem, dass die Zahl, die der Client ganz und gar nichts 
mir der ursprünglichen zu tun hat.

Der Client Code-Ausschnitt sieht so aus:
1
ctr=malloc(sizeof(int));
2
if((recv(IDMySocket, ctr, 1,0))!=0)
3
printf("%d\n",ctr);
4
free(ctr);

von Kaj (Gast)


Lesenswert?

Gehts auch genauer?
Welches Betriebssystem?
Was schickst du, und was empfängst du?
Hast du an Netzwerk-Byteorder gedacht?

Sorry, aber bei meiner Glaskugel ist der Akku grad alle.
Ansonsten ist dein Fehler in Zeile 42 zu finden...

von Jojo S. (Gast)


Lesenswert?

Ein gerne gemachter Fehler bei recv() ist anzunehmen das in einem Aufruf 
alle Bytes ankommen. Man muss aber in einer Schleife solange Bytes 
sammeln bis ist=sollanzhl ist oder recv() einen Fehler oder anz=0 => 
Verbindungsabbruch meldet.

von QX (Gast)


Lesenswert?

Ich benutze ein Beaglebone black, mit Neutrino RTOS Betriebssytem.

Mein Sendeteil sieht so aus:
1
if(send(IDclient,&ADCbuffer[n],1,0)!=-1)
2
printf("Sende Signal:%d\n",ADCbuffer[n]);

ADCbuffer ist ein uint32_t Array. In dem Fall schicke ich eine "1".
Erhalte eine "134529632".

von QX (Gast)


Lesenswert?

Aber für was steht dann das size an der 3.Stelle in der recv-Fkt. ?

von Kaj (Gast)


Lesenswert?

QX schrieb:
> In dem Fall schicke ich eine "1".
Schickst du eine "1", oder eine '1' oder eine 1?

von Kaj (Gast)


Angehängte Dateien:

Lesenswert?

QX schrieb:
> Aber für was steht dann das size an der 3.Stelle in der recv-Fkt. ?
Aus Linux, man recv

von Jojo S. (Gast)


Lesenswert?

Das Size steht schon für die Sollanzahl, aber es ist nicht garantiert 
das die Daten tatsächlich in einem Rutsch kommen. Gilt hauptsächlich für 
non-blocking sockets, aber auch bei blocking muss man mit Fehlern oder 
Verbindungsabbruch rechnen. Und TCP vorausgesetzt.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

QX schrieb:
> Der Client Code-Ausschnitt sieht so aus:


> ctr=malloc(sizeof(int));
> if((recv(IDMySocket, ctr, 1,0))!=0)
> printf("%d\n",ctr);
> free(ctr);

ctr ist also ein Pointer.


Mit Deiner printf-Anweisung gibst Du aber nicht das aus, worauf der 
Pointer zeigt, sondern den Pointer selbst.


Lies Dir mal in Deinem C-Buch das Kapitel über Pointer und deren 
Dereferenzierung durch.

von Marius W. (mw1987)


Lesenswert?

QX schrieb:
> ctr=malloc(sizeof(int));
> if((recv(IDMySocket, ctr, 1,0))!=0)
> printf("%d\n",ctr);
> free(ctr);

Dein printf sieht komisch aus... ctr ist ein Pointer auf einen Integer. 
Der hat mindestens 2 Byte, du empfängst hier aber nur ein Byte! Damit 
ist schonmal mindestens die Hälfte deines ctr undefiniert. Außerdem 
müsste im printf *ctr stehen, weil du ja nicht den Pointer, sondern den 
Wert auf den er zeigt ausgeben willst!

Gruß
Marius

von guest (Gast)


Lesenswert?

Jojo S. schrieb:
> Das Size steht schon für die Sollanzahl

Nicht wirklich. Das steht eigentlich für die Buffergröße, also die 
Maximalanzahl von Bytes, die recv da reinschreiben darf.
Steht ja auch explizit so in dem von Kaj geposteten Screenshot

von Kaj (Gast)


Lesenswert?

Jojo S. schrieb:
> Das Size steht schon für die Sollanzahl

Glaub ich eher weniger...
http://www.qnx.com/developers/docs/6.4.1/neutrino/lib_ref/r/recv.html
1
len
2
The size of the buffer.
Nix mit Sollanzahl, sondern länge des Puffers in den geschrieben wird.

von Martin K. (martinko)


Lesenswert?

OK,

1. Du sendest einzeln die Werte aus einem uint32_t Array. Das sind in 
jedem Fall unsigned ints mit 32 Bit, also 4 Byte pro Wert
2. beim senden gibst Du als größe aber nur 1 Byte an
3. Du beachtest die Byte-Order nicht, ich kenne das Beagleboard nicht 
und ich kenne den Empfänger nicht, ist die bei beiden gleich?
4. Du versucht in einen signed int zu lesen den Du dynamisch allokierst
5. auch beim lesen gibst Du nur eine Größe von 1 Byte an
6. Du gibst im printf nicht den Wert aus den der int Zeiger enthält, 
sondern nur den Zeiger, erhält also dessen Adresse als Ausgabe

Wenn Du weiter einzelne Werte senden willst:
a) Wandle das zu sendende Wort mit hton in die Netzwerkdarstellung um
b) sende genügend Bytes z.B. mit 
send(IDclient,&ADCbuffer[n],1*sizeof(uint32_t),0)
c) verwende den richtigen Datentyp uint32_t* Car = 
malloc(sizeof(uint32_t));
d) Lese auch genügend Bytes mit recv(IDMySocket, ctr, 
1*sizeof(uint32_t),0)
e) wandle das gelesene wieder in die Host Darstellung um: *ctr = 
ntoh(*ctr)
f) referenzierten den Zeiger zur Ausgabe: *ctr und nicht nur *ctr im 
printf

zu allen Funktionen gibt es im Netz genügend Infos und Beispiele!

Es ist richtig das die Datenpakete von den TCP/IP Stacks nicht unbedingt 
am Stück gesendet oder empfangen werden müssen. Aber wenn die Pakete 
klein genug sind, nicht irgendwo fragmentiert werden und NAGLE nicht 
abgeschaltet wurde, dann ist es doch sehr wahrscheinlich, dass das an 
Bytes ankommt, was auch gesendet wurde. Wenn Du mit deinem einen Wert 
klar kommst und größere Pakete senden willst, dann kannst Du immer noch 
weiter sehen….

Gruß Martin

von guest (Gast)


Lesenswert?

Martin K. schrieb:
> d) Lese auch genügend Bytes mit recv(IDMySocket, ctr,
> 1*sizeof(uint32_t),0)

Und überprüfe ob auch tatsächlich 1*sizeof(uint32_t) Bytes gelesen 
wurden!

von Rolf Magnus (Gast)


Lesenswert?

Jojo S. schrieb:
> Das Size steht schon für die Sollanzahl, aber es ist nicht garantiert
> das die Daten tatsächlich in einem Rutsch kommen. Gilt hauptsächlich für
> non-blocking sockets, aber auch bei blocking muss man mit Fehlern oder
> Verbindungsabbruch rechnen. Und TCP vorausgesetzt.

Das hat nichts mit Fehlern oder Verbindungsabbrüchen zu tun. Es wird das 
zurückgeliefert, was verfügbar ist. Das muß auch bei normaler Verbindung 
nicht unbedingt soviel sein, wie man als Size angegeben hat. Es muß auch 
nicht soviel sein, wie der Sender am Stück an seine send-Funktion 
übergeben hat.
Deshalb muß man bei solchen Syscalls wie recv oder read eigentlich in 
einer Schleife so lange lesen, bis man die gewünschte Datenmenge 
erhalten hat. Und man muss auf Fehler prüfen, denn nicht jede Fehler 
bedeutet kompletten Abbruch, sondern manch einer erfordert einfach einen 
erneuten Leseversuch.

QX schrieb:
> ctr=malloc(sizeof(int));

Warum allokierst du den int denn dynamisch?

Martin K. schrieb:
> Es ist richtig das die Datenpakete von den TCP/IP Stacks nicht unbedingt
> am Stück gesendet oder empfangen werden müssen. Aber wenn die Pakete
> klein genug sind, nicht irgendwo fragmentiert werden und NAGLE nicht
> abgeschaltet wurde, dann ist es doch sehr wahrscheinlich, dass das an
> Bytes ankommt, was auch gesendet wurde.

Ja, wenn x und wenn y und wenn z, dann geht's wahrscheinlich...
Und nächste Woche kommt die nächste Frage, warum's nicht mehr klappt, 
wenn er größere Pakete sendet.

von Der Andere (Gast)


Lesenswert?

Martin K. schrieb:
> Es ist richtig das die Datenpakete von den TCP/IP Stacks nicht unbedingt
> am Stück gesendet oder empfangen werden müssen. Aber wenn die Pakete
> klein genug sind, nicht irgendwo fragmentiert werden und NAGLE nicht
> abgeschaltet wurde, dann ist es doch sehr wahrscheinlich, dass das an
> Bytes ankommt, was auch gesendet wurde.

Ja super Aussage, leider unbrauchbar!

Wir haben mal Wochen einen selten auftauchenden Fehler in einer 
selbstgeschriebenen recht umfangreichen Mittelware gesucht, bis wir 
durch Codeanalyse das tatsächliche Problem gefunden hatten. Ursache war, 
dass in der untersten Ebene erst ein 2 Byte Wert für die Größe des 
nachfolgenden Datenblocks und dann die Daten selbst gesendet und 
empfangen wurden.
Der Empfänger hat zwar schön in einer Schleife die Daten 
zusammengesammelt, aber bei der 2Byte Länge ist er davon ausgegangen, 
dass die ja in einem Rutsch kommt. Klar aber nur bei 99,995% aller 
Fälle.

Merke: Man kann sich NIE NIE NIE sicher sein, dass man alle Bytes auf 
einmal empfängt!

von Karl H. (kbuchegg)


Lesenswert?

Der Andere schrieb:
> Martin K. schrieb:
>> Aber wenn die Pakete
>> klein genug sind, nicht irgendwo fragmentiert werden und NAGLE nicht
>> abgeschaltet wurde, dann ist es doch sehr wahrscheinlich, dass das an
>> Bytes ankommt, was auch gesendet wurde.
>
> ....
>
> Merke: Man kann sich NIE NIE NIE sicher sein, dass man alle Bytes auf
> einmal empfängt!

Oder auf Deutsch: machs gleich richtig, dann hast du weniger Probleme, 
die dich beissen können.
Jede windige Annahme, die man erst mal akzeptiert, gerät im laufe der 
Zeit in Vergessenheit und wartet nur darauf zuzuschlagen. Natürlich 
dann, wenn sie maximalen Schaden anrichten kann.

: Bearbeitet durch User
von Der Andere (Gast)


Lesenswert?

Karl H. schrieb:
> Jede windige Annahme, die man erst mal akzeptiert, gerät im laufe der
> Zeit in Vergessenheit und wartet nur darauf zuzuschlagen. Natürlich
> dann, wenn sie maximalen Schaden anrichten kann.

Jepp, ich habe schon einige Arbeitszeit damit verbraten solche 
Zeitbomben zu finden. Eigene und noch öfter die von anderen.

von Martin K. (martinko)


Lesenswert?

Karl H. schrieb:
> Der Andere schrieb:
>> Martin K. schrieb:
>>> Aber wenn die Pakete
>>> klein genug sind, nicht irgendwo fragmentiert werden und NAGLE nicht
>>> abgeschaltet wurde, dann ist es doch sehr wahrscheinlich, dass das an
>>> Bytes ankommt, was auch gesendet wurde.
>>
>> ....
>>
>> Merke: Man kann sich NIE NIE NIE sicher sein, dass man alle Bytes auf
>> einmal empfängt!
>
> Oder auf Deutsch: machs gleich richtig, dann hast du weniger Probleme,
> die dich beissen können.
> Jede windige Annahme, die man erst mal akzeptiert, gerät im laufe der
> Zeit in Vergessenheit und wartet nur darauf zuzuschlagen. Natürlich
> dann, wenn sie maximalen Schaden anrichten kann.

Ja, aber: Meint Ihr das jemand der in gerade einmal einem halben Dutzend 
Code Zeilen so mit Datentypen und Zeigern und unsigned oder nicht und 
Pointer oder nicht um sich wirft das hin bekommt? Es gibt ja immer noch 
die TODO Kommentare - die natürlich auch zeitnah bearbeitet werden 
müssen ;-)

Gruß Martin

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.