Probleme beim Senden von mehreren Datenpaketen über Winsocks
lima-city → Forum → Programmiersprachen → C/C++ und D
adresse
anzahl
aufpassen
buffer
code
datenpaket
datum
empfangen
funktion
idee
netz
paar
paket
problem
programm
protokoll
sache
senden
server
zeiger
-
Hallo,
ich schreibe momentan ein Programm, welches einige hundert mal pro Sekunde Datenpakete an einen Server sendet. Das Problem dabei ist, dass beim senden von mehr als zwei Datenpaketen (z.B. zwei Strings) nur das erste Paket ankommt. Hier ein Beispiel:
// Client: int SendAVORunning() { char buffer[256]; strcpy(buffer, "AVO running!"); int bytesToSend = strlen("AVO running"); if(send(connectedSocket, buffer, bytesToSend, 0) != bytesToSend) return -1; return 0; } void main() { //...WSASetup; Socket initialisieren;Verbindung aufbauen -> geht alles SendAVORunning(); SendAVORunning(); }
// Server: char* RecvAVOStatus() { char buffer[256]; int result = recv(connectedSocket, buffer, 256, 0); buffer[result] = '\0'; return buffer; } void main() { //...WSASetup; Socket initialisieren;listen und accept -> geht alles RecvAVOStatus(); RecvAVOStatus(); }
...diese Kommunikation ergibt zwar keinen Sinn, soll aber nur das Problem verdeutlichen.
Die erste "AVO running" Nachricht kommt an, die zweite nicht. Ich bin etwas verzweifelt, da ich schon einige Tage versucht habe das Problem zu lösen - leider ohne Erfolg.
PS: Ich verwende als Include WinSock2.h (+ ws2_32.lib) und gebe bei WSAStartup() Version 2.0 an.
Beitrag zuletzt geändert: 23.11.2010 15:58:31 von primenic -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage
-
sektor schrieb: Also bei Netzwerkprogrammen wäre vielleicht noch interessant zu wissen, welches Protokoll du verwendest.
Ansonsten kannst du mal mit einem Programm wie Wireshark schauen, was denn tatsächlich übers Netz geht, um zu sehen ob nicht gesendet oder nicht emfpangen wird.
Also Protokoll ist TCP. Die Datenpakete werden gesendet und kommen bei der Gegenstelle auch an.
xilebo schrieb: Kann es sein, dass du den Buffer nach dem Senden/Empfangen leeren musst?
(Nur so 'ne Idee, ohne mich jetzt näher damit befasst zu haben...)
Beim Empfangen werden die Daten, die empfangen werden, ja aus dem Empfangsbuffer schon herausgenommen. - Liegt da vielleicht das Problem?: Wenn ich statisch immer 256 bytes in das char Array einlesen kann es doch auch sein, dass ich "zu viele" Bytes (d.h. auch schon welche vom nachfolgenden Datenpaket) einlese - oder? -
Hallo primenic.
Was das Empfangen angeht, hast Du recht.
Mit recv() liest Du alle Daten aus dem Empfangspuffer, d.h. insbesondere, wenn mehrere Packete im Empfangspuffer liegen, dann werden alle Pakete auf einmal nach buffer kopiert und aus dem Empfangspuffer gelöscht.
Aber wenn Du Dir den Empfangspuffer einmal ausgeben lässt, dann müsstest Du das eigentlich sehen.
Wenn zwei Pakete empfangen wurden, dann muss die Ausgabe nämlich
AVO running!AVO running!
sein.
Allerdings musst Du bei Deiner Empfangsfunktion aufpassen:
1.)
Du hast buffer nicht als 'static' deklariert, d.h. nach verlassen der Funktion ist der Zeiger auf buffer ungültig, was zu einer Speicherzugriffsverletzung führen kann.
2.)
recv() gibt die Anzahl der empfangenen Bytes zurück und nicht notwendigerweise die Anzahl der nach buffer kopierten Bytes.
D.h. wenn weniger als 256 Bytes empfangen wurden, dann entspricht der Rückgabewert der Anzahl der kopierten Bytes.
Wenn aber 256 Bytes oder mehr empfangen wurden, dann werden 256 Bytes nach buffer kopiert und aus dem Empfangspuffer gelöscht. Der Rückgabewert von recv() ist in diesem Fall aber größer oder gleich 256.
Daher wird dann
buffer[result] = '\0';
eine Speicherzugriffsverletzung auslösen oder zumindest deinen Stack unvorhersehbar verändern, weil 'result' dann 256 oder größer ist während buffer[255] die letzte gültige Adresse ist.
Um die restlichen Bytes abzuholen muss man recv() wiederholt aufrufen.
Um solche Sachen zu vermeiden kann man vor den eigentlichen Daten immer erst die Größe der Daten versenden:
send(connectedSocket, &bytesToSend, sizeof(int), 0)
Beim Lesen dann entsprechend umgekehrt (und Byteorder beachten).
So kann man dann die einzelnen Pakete wieder auseinanderhalten.
Wenn man die Sache noch sicherer machen will, dann sendet man noch ein paar Steuercodes mit z.B. 'DATA_START' vor den Nutzaten und 'DATA_END' nach den Nutzdaten.
-
darkpandemic schrieb:
Allerdings musst Du bei Deiner Empfangsfunktion aufpassen:
1.)
Du hast buffer nicht als 'static' deklariert, d.h. nach verlassen der Funktion ist der Zeiger auf buffer ungültig, was zu einer Speicherzugriffsverletzung führen kann.
2.)
recv() gibt die Anzahl der empfangenen Bytes zurück und nicht notwendigerweise die Anzahl der nach buffer kopierten Bytes.
D.h. wenn weniger als 256 Bytes empfangen wurden, dann entspricht der Rückgabewert der Anzahl der kopierten Bytes.
Wenn aber 256 Bytes oder mehr empfangen wurden, dann werden 256 Bytes nach buffer kopiert und aus dem Empfangspuffer gelöscht. Der Rückgabewert von recv() ist in diesem Fall aber größer oder gleich 256.
Daher wird dann
buffer[result] = '\0';
eine Speicherzugriffsverletzung auslösen oder zumindest deinen Stack unvorhersehbar verändern, weil 'result' dann 256 oder größer ist während buffer[255] die letzte gültige Adresse ist.
Stimmt! Darüber habe ich mir noch gar keine Gedanken gemacht
darkpandemic schrieb:
Um solche Sachen zu vermeiden kann man vor den eigentlichen Daten immer erst die Größe der Daten versenden:
send(connectedSocket, &bytesToSend, sizeof(int), 0)
Beim Lesen dann entsprechend umgekehrt (und Byteorder beachten).
So kann man dann die einzelnen Pakete wieder auseinanderhalten.
Wenn man die Sache noch sicherer machen will, dann sendet man noch ein paar Steuercodes mit z.B. 'DATA_START' vor den Nutzaten und 'DATA_END' nach den Nutzdaten.
Ja an sowas hab ich auch schon gedacht, aber da ich bei dem ersten Versuch anscheinend vergessen hatte, die Größe des nachfolgenden Datenpakets auszulesen, kam da auch nur Müll raus .
Aber danke, dass du mich nochmal auf diese Idee gebracht hast. Habs jetzt so gelöst:
struct NET_DATA { DWORD length; DWORD type; }
Beim senden sende ich halt einfach erst eine gefüllte NET_DATA Struktur und lese halt beim Empfangen erst die Struktur und dann das Datenpaket ein. -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage