send/recv unter Windows 7 (64 Bit) - seltsames Verhalten [gelöst]



  • Hallo,
    Ich versuche gerade eine Server-Client Programmierung (mit Visual C++ 2010). Dabei tritt beim Testen ein seltsames Verhalten auf. Ich habe folgende Programm-Codes:

    Server:

    #include "stdafx.h"
    #include <Windows.h>
    
    #define BUFFERSIZE 786436*4
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	SOCKET server;
    	SOCKET client;
    
    	char* ipStr = "192.168.0.21";
    	char* portStr = "17700";
    
    	struct sockaddr_in serverAddr;
    	u_long port = (u_long)atol(portStr);
    	serverAddr.sin_addr.s_addr = inet_addr(ipStr);
    	serverAddr.sin_port = htons(port);
    	serverAddr.sin_family = AF_INET;
    
    	struct sockaddr_in cli;
    	int cli_size = sizeof(cli);
    
    	unsigned char* daten = new unsigned char[BUFFERSIZE];
    	for(unsigned int x=0;x<BUFFERSIZE;x++)
    	{
    		daten[x] = x;
    	}
    	unsigned int bytes,temp;
    
    	WSADATA	wsa;
    	if (WSAStartup(MAKEWORD(1, 1), &wsa))
    	{
    		printf("WSAStartup() failed, %d\n", WSAGetLastError());
    		system("pause");
    		return 1;
    	}
    	server = socket(serverAddr.sin_family, SOCK_STREAM, IPPROTO_TCP);
    	if (server == INVALID_SOCKET)
    	{
    		printf("socket() failed, %d\n",WSAGetLastError());
    		system("pause");
    		return 2;
    	}
    
    	if (bind(server, (struct sockaddr*) &serverAddr, sizeof(serverAddr)) == -1)
    	{
    		printf("bind() failed, %d\n",WSAGetLastError());
    		system("pause");
    		return 3;
    	}
    
    	if (listen(server, 3) == -1)
    	{
    		printf("listen () failed, %d\n",WSAGetLastError());
    		system("pause");
    		return 4;
    	}
    
    	printf("Warte auf Verbindung...\n");
    	client = accept(server, (sockaddr*)&cli, &cli_size);
    
    	printf("Sende %d Bytes\n\n",BUFFERSIZE);
    	bytes = 0;
    	while(bytes < BUFFERSIZE)
    	{
    		temp = send(client, (const char*)&daten[bytes], BUFFERSIZE-bytes, 0);
    		if (temp == -1)
    		{
    			printf("Client %d hat die Verbindung getrennt.\n",client);
    			closesocket(client);
    			client = INVALID_SOCKET;
    			break;
    		}
    		else
    		{
    			printf("Inhalt gesendet (%d Bytes, erste 12 Bytes werden angezeigt):\n",temp);
    			for(unsigned int x=0;x<12;x++)
    			{
    				printf("%d ",daten[bytes+x]);
    			}
    			printf("\n");
    			bytes += temp;
    		}
    		printf("\n");
    	}
    
    	system("pause");
    	return 0;
    }
    

    Client:

    #include "stdafx.h"
    #include <windows.h>
    
    #define BUFFERSIZE 786436*4
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	WSADATA wsa;
    	if (WSAStartup(MAKEWORD(1, 1), &wsa))
    	{
    		char* str = new char[1024];
    		printf("WSAStartup() failed, %d\n", (unsigned long)WSAGetLastError());
    	}	
    	char* ipStr = "192.168.0.21";
    	char* portStr = "17700";
    
    	struct sockaddr_in addr;
    	u_long port = (u_long)atol(portStr);
    	addr.sin_addr.s_addr = inet_addr(ipStr);
    	addr.sin_port = htons(port);
    	addr.sin_family = AF_INET;
    
    	SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    	connect(clientSocket, (sockaddr*)&(addr), sizeof(addr));
    
    	unsigned char* buffer = new unsigned char[BUFFERSIZE];
    	unsigned int bytes = 0;
    	unsigned int temp;
    
    	printf("Empfange %d Bytes\n\n",BUFFERSIZE);
    	bytes = 0;
    	while(bytes<BUFFERSIZE)
    	{
    		temp = recv(clientSocket, (char*)&buffer[bytes],BUFFERSIZE-bytes, 0);
    		if (temp == -1)
    		{
    			printf("Verbindung zum Server unterbrochen (Body-Empfang)\nWSAGetLastError: %d\n",WSAGetLastError());
    			return 2;
    		}
    		else
    		{
    			printf("Inhalt empfangen (%d Bytes, erste 12 Bytes werden angezeigt):\n",temp);
    			for(unsigned int x=0;x<12;x++)
    			{
    				printf("%d ",buffer[bytes+x]);
    			}
    			printf("\n");
    			bytes += temp;
    		}	
    		printf("\n");
    	}
    
    	system("pause");
    	return 0;
    }
    

    So weit, so gut...
    Ich starte zuerst den Server unter Windows XP (32 Bit) auf einem anderen Rechner (IP 192.168.0.21). Dann starte ich den Client auf meinem Rechner unter Windows 7 (64 Bit).

    Wenn alles gestartet wurde, sieht man in der Konsole des Servers folgende Ausgabe:

    Warte auf Verbindung...
    Sende 3145744 Bytes
    
    Inhalt gesendet (3145744 Bytes, erste 12 Bytes werden angezeigt):
    0 1 2 3 4 5 6 7 8 9 10 11
    
    Drücken Sie eine beliebige Taste . . .
    

    und in der Konsole des Clients folgendes:

    Empfange 3145744 Bytes
    
    Inhalt empfangen (3145744 Bytes, erste 12 Bytes werden angezeigt):
    0 1 2 3 4 5 6 7 8 9 10 11
    
    Drücken Sie eine beliebige Taste . . .
    

    Das passt soweit auch, denke ich. Es wird das ausgegeben was ich erwarte.
    Wenn ich aber den Server ebenfalls auf meinem Rechner (Windows 7 (64 Bit)) laufen lasse, bekomme ich im Client folgende Ausgabe (IP-Adressen im Quellcode entsprechend angepasst und Server und Client neu kompiliert):

    Empfange 3145744 Bytes
    
    Inhalt empfangen (2776364 Bytes, erste 12 Bytes werden angezeigt):
    228 229 230 231 232 233 234 235 236 237 238 239
    
    Inhalt empfangen (369380 Bytes, erste 12 Bytes werden angezeigt):
    0 1 2 3 4 5 6 7 8 9 10 11
    
    Drücken Sie eine beliebige Taste . . .
    

    Die Ausgabe im Server bleibt die gleiche.

    Was passiert denn da? Das recv() wurde wohl zweimal gemacht. Ok, das kann ich noch verstehen, denn das kann vorkommen bei zu großen Portionen. Aber dass das nicht in der richtigen Reihenfolge kommt, das verwundert mich!

    Was mache ich da falsch?

    MfG

    EDIT: Habe mittlerweile herausgefunden, dass es nicht an Windows 7 liegt, sondern an der Tatsache dass mein Windows 7 ein 64 Bit-Betriebssystem ist. Denn wenn der Server unter einem 32-Bit-Windows 7 läuft, funktioniert alles.

    Ich weiß aber immer noch nicht was ich falsch mache... 😞

    EDIT 2: Wenn ich #define BUFFERSIZE 786436/4 schreibe, klappts wieder, bei #define BUFFERSIZE 786436/2 nicht mehr. Weiß mir jemand wo die Grenze liegt um eine Aufspaltung meiner Daten zu verhindern? Oder weiß jemand wie ich es schaffe die Daten beim Empfänger wieder in die richtige Reihenfolge zu bekommen?

    MfG



  • Dieser Thread wurde von Moderator/in SeppJ aus dem Forum C++ (auch C++0x) in das Forum WinAPI verschoben.

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

    Dieses Posting wurde automatisch erzeugt.



  • Also erstmal muss ich zugeben, dass ich mich mit winAPI überhaupt nicht auskenne.

    Aber normalerweise sollte TCP dafür sorgen, dass alles in der richtigen Reihenflge ankommt.
    Und IP (oder auch TCP, bin mir nicht sicher) sorgt dafür, dass die Pakete aufgespalten werden, wenn sie zu groß sind.

    Was da schiefgeht weiß ich leider auch nicht.



  • @Q: Danke für deine Antwort. Hab schon befürchtet dass ich ignoriert werde weil ich vielleicht ne Foren-Regel mißachtet habe 😉

    Das mit dem TCP dachte ich mir auch genauso wie du schreibst...

    Also ich hab natürlich mal weiter herumprobiert. Die Sache wird immer merkwürdiger. Auf dem Rechner meines Kollegen, auch Win7-64 Bit funktioniert es nämlich. Das was gesendet wird, kommt in der richtigen Reihenfolge an.

    Auf dem Rechner eines weiteren Kollegen (ebenfalls Win7-64 Bit) funktionierts wieder nicht.

    Also ich weiß ja nicht ob man das pauschal auf das Betriebssystem oder auf die Anzhal der Bit schieben kann. Es ist halt bisher nur unter Win7 64-Bit aufgetreten, aber nicht auf allen Win7-64 Bit Rechnern.

    Vielleicht liegts ja auch an der Netzwerkkarte oder an deren Treiber. Ist die Netzwerkkarte bzw. der Treiber überhaupt im Spiel wenn ich Sender und Empfänger auf ein und demselben Rechner betreibe (also von z.B. 192.168.0.60 sende und von 192.168.0.60 empfange)?

    EDIT: Ich habe noch was herausgefunden. Und zwar habe ich hier im lokalen Netzwerk zwei Rechner auf denen es nicht funktioniert, dass Server und Client auf dem selben Rechner laufen. Ich nenne sie mal Rechner A und Rechner B.

    Also:
    Server auf Rechner A und Client auf Rechner A => funktioniert nicht
    Server auf Rechner B und Client auf Rechner B => funktioniert nicht

    Aber
    Server auf Rechner A und Client auf Rechner B => funktioniert !!!

    Das Problem scheint wohl nur zu bestehen wenn ich sowohl Server als auch Client auf dem selben Rechner laufen lasse...

    (Ich habe bereits den neuesten Treiber für meine Netzwerkkarte. Ich habe diesen von Herstellerseite selber heruntergeladen und installiert, also nicht per Windows-Treiberupdate.)



  • SchlechterInformatiker schrieb:

    @Q: Danke für deine Antwort. Hab schon befürchtet dass ich ignoriert werde weil ich vielleicht ne Foren-Regel mißachtet habe 😉

    Nönö, das passt schon 😉

    An TCP/IP liegt es nicht. Wie Q schon geschrieben hat, stellt TCP sicher, dass alles in der richtigen Reihenfolge ankommt.

    Also muss es fast an deinem/eurem Code liegen.

    Ich hatte mir den auch gestern schon angesehen, nur sieht für mich alles OK aus, weiss nicht was da schief gehen sollte.

    Sicher ist es theoretisch möglich, dass Windows oder ein Treiber Mist baut, aber die Wahrscheinlichkeit schätze ich als sehr gering ein.

    Hat zwar (ziemlich sicher) mit dem Problem nix zu tun, aber etwas was ich ganz grässlich finde:

    #define BUFFERSIZE 786436*4
    

    Argh.
    Entweder den Ausdruck klammern, oder gleich ne static const verwenden:

    #define BUFFERSIZE (786436*4)
    // oder noch besser
    static size_t const BUFFERSIZE = 786436*4;
    

    Und nochwas: ist das auch 1:1, aufs Zeichen genau der Code mit dem du getestet hast?



  • Ist die Ausgabe mit printf als %d überhaupt richtig? Müsste doch %c sein.



  • Sorry war quatsch.



  • @hustbaer: Du hast vollkommen Recht, das ist grässlich. Das habe ich mittlerweile während weiterer Tests auch durch "#define BUFFERSIZE (786436*4)" ersetzt.
    Ursprünglich hatte ich natürlich anderen Code aber ich konnte das Problem auf diesen Code herunterbrechen. Aber das ist genau der Code mit dem ich es getestet habe - und mit dem funktionierts auch schon nicht. Dann ist klar dass es im "richtigen" Code auch nicht funktionieren kann.

    Hat sonst noch jemand Ideen?
    Meint ihr ich soll mal an Microsoft schreiben? Antworten die auf sowas überhaupt?



  • SchlechterInformatiker schrieb:

    Aber das ist genau der Code mit dem ich es getestet habe - und mit dem funktionierts auch schon nicht.

    Ja, das wollte ich wissen. Kommt viel zu oft vor, dass Leute Code für's Posten im Forum "zusammenkürzen", und dabei die Fehlerursache entfernen. Wollte nur sicher gehen dass du das nicht gemacht hast 🙂

    Also ich bin auch mehr oder weniger Ratlos. Was du vielleicht noch probieren könntest:
    * Auf 127.0.0.1 binden statt auf 192.168.0.21
    * Im Server mehrere kleinere send() machen
    * Im Client mehrere kleinere recv() machen
    * In Server und Client mehrere kleinere send()/recv() machen
    * Falls du bisher immer Release-Versionen getestet hast, versuch mal ne Debug-Version
    * Wenn es einfach geht, probier mal den selben Code mit einem anderen Compiler zu compilieren (evtl. MinGW oder ne ältere/neuere Studio Version)

    Das dürfte zwar eigentlich alles keinen Unterschied machen, aber wenn es einen macht, wäre es u.U. interessant.

    Meint ihr ich soll mal an Microsoft schreiben? Antworten die auf sowas überhaupt?

    Ich würde vorschlagen: poste es erstmal im MSDN Forum.

    http://social.msdn.microsoft.com/Forums/en/category/windevgeneral

    Schätze das "General Windows Development Issues" wird am besten passen (bei "Windows SDK" scheint's eher um das SDK selbst zu gehen - Installation usw., nicht um Dinge die man damit/darüber ansprechen kann).

    Wenn dabei nix rauskommt ausser "müsste eigentlich gehen", dann ruf beim Support an. Ich weiss nicht ob es eine Option gibt, einen Support Case aufzumachen, ohne dass die Chance besteht dass man dafür zahlen muss. Wenn sich rausstellt dass es ein Bug von Microsoft ist, dann ist der Support Case aber soweit ich weiss gratis.
    Bei einigen MSDN Subscriptions sind auch ein paar gratis Support Cases dabei - falls du oder jmd. anderer in deiner Firma eine passende MSDN Subscription hat, wäre das auch eine Option.
    WENN du das machst, also einen Support Case aufmachen, dann kann ich dir auf jeden Fall garantieren, dass dir jmd. antwortet 🙂

    Aber wie gesagt: ich würde es erst nochmal im MSDN Forum posten.

    Und wäre nett wenn du uns auf dem laufenden hältst.



  • @hustbaer: Vielen Dank für deine Tips.

    Mit kleineren send() und recv() hab ich es schon versucht, das funktioniert. Aber das macht die Sache glaub nicht sicherer, sondern nur unwahrscheinlicher dass der Fehlerfall auftritt.

    Ich melde mich falls ich was herausgefunden habe.

    EDIT: Das Benutzern der IP 127.0.0.1 bzw. die Debug-Variante lösen das Problem auch nicht.



  • Probier mal die neuste WINSOCK Version zu initialisieren.

    ws2_32.lib

    WSADATA iws;
    
    if( WSAStartup(MAKEWORD(2,2), &iws) != 0 ) {
    	printf("\nWSAStartup() error : %i\n",WSAGetLastError());
    	return 1;
    }
    


  • @-lowbyte- : Danke für den Tip. Hat aber leider auch nicht geholfen. Aus dem Microsoft Forum hab ich auch noch keine Antwort 😞



  • Ich habe die Ursache gefunden: Wenn ich meine Firewall "ZoneAlarm" deaktiviere, dann funktioniert alles. Wenn die Firewall eingeschaltet ist, dann kommen die Paktete in der falschen Reihenfolge.

    Mein PC befindet sich in der "sicheren Zone", auch meine IP habe ich explizit als "sichere Zone" angegeben. Außerdem beantworte ich alle Anfragen, die beim Start eines neu kompilierten Servers bzw. Clients auftauchen, mit "zulassen".

    Wenn gar keine Daten durchkommnen würden, dann hätte ich ja noch Verständnis dafür aber sowas???

    Von daher: keine Ahnung was das soll. Vielleicht lässt sich da was in der kommerziellen Version was entsprechendes einstellen, aber bei der Freeware-Version von ZoneAlarm wohl nicht. Ich kann von einem Kunden aber nicht verlangen solche Einstellungen vorzunehmen oder sich die kommerzielle Version zu kaufen. Ich wüsste nicht was ich als Programmierer machen kann damit es in jedem Fall funktioniert.

    Danke an alle für eure Hilfe!



  • Ich denke man kann vom Kunden verlangen, dass er sich so einen Quatsch wie ZoneAlarm nicht installiert. :p



  • Na das ist ja mal interessant 🙂

    SchlechterInformatiker schrieb:

    Von daher: keine Ahnung was das soll.

    Naja, ganz einfach. Entweder ZoneAlarm ist verbuggt, oder Windows' Interface zu Desktop-Firewalls ist verbuggt.

    Welches von beiden kannst du einfach ausprobieren: installiere eine andere (nicht-Microsoft) Desktop-Firewall. Spontan fällt mir da die Comodo Personal Firewall als Kandidat ein, die gibt's AFAIK immer noch in einer gratis Version.
    Wenn du mit der das selbe Problem hast, dann liegt der Verdacht nahe dass Windows hier nen Bug haben könnte. In dem Fall solltest du das an MS reporten, bzw. in deinem MSDN Forum Thread darauf hinweisen.

    Wenn es aber mit einer anderen Desktop-Firewall geht, liegt es fast sicher an ZoneAlarm. Dann solltest du den Bug an CheckPoint (ZoneAlarm) melden.

    Bzw. selbst wenn es mit verschiedenen Desktop-Firewalls passiert, könntest du mal die Hersteller dieser anschreiben. Wenn es wirklich ein MS Bug sein sollte, dann ist da mehr Druck dahinter, wenn eine Firma wie Comodo oder CheckPoint bei MS nachfragt was das soll 🙂

    SchlechterInformatiker schrieb:

    (...) Ich kann von einem Kunden aber nicht verlangen solche Einstellungen vorzunehmen oder sich die kommerzielle Version zu kaufen. Ich wüsste nicht was ich als Programmierer machen kann damit es in jedem Fall funktioniert.

    Du kannst einen "Known Issues" Bereich im Readme machen, und da reinschreiben dass das Dinge mit Version so-und-so von ZoneAlarm Probleme macht.

    Ansonsten kannst du eins machen, was vermutlich sehr hohe Erfolgschancen hat: zerteile grosse send/recv Aufrufe in mehrere kleinere. Ermittle die Grenze ab der es schief geht, runde auf Zweierpotenz ab, und nimm dann 1/4 davon - oder so.

    Vermutlich sehr hohe Erfolgschancen deswegen, weil...: wenn das mit allen/vielen Anwendungen auftreten würde, wäre der Fehler längst tausendfach aufgefallen, und sicher schon längt behoben. Und das einzig "spezielle" was deine Programme machen, ist ziemlich grosse Datenstücke mit einem einzigen send/recv Aufruf zu versenden/empfangen. Daher vermute ich, dass das Problem bei kleineren Blöcken einfach nicht auftritt, und das auch der Grund ist warum es bisher noch nicht aufgefallen ist/nicht behoben wurde.



  • cooky451 schrieb:

    Ich denke man kann vom Kunden verlangen, dass er sich so einen Quatsch wie ZoneAlarm nicht installiert. :p

    100 Punkte. Denn da ist mehr verbuggt als man denkt!



  • @hustbaer: Also ich habe jetzt mal bei mir ZoneAlarm deinstalliert und COMODO installiert. Mit COMODO funktionierts. Ich habe gesehen, dass beim allerersten Start meines Clients mehrere recv() Aufrufe stattgefunden haben obwohl der Server nur ein send() machen musste. Das lag wohl daran dass ich erst ein paar mal auf "zulassen" klicken musste. Die Pakete sind aber in der richtigen Reihenfolge empfangen worden!!! So wie es sein soll, alles wunderbar.

    hustbaer schrieb:

    Du kannst einen "Known Issues" Bereich im Readme machen, und da reinschreiben dass das Dinge mit Version so-und-so von ZoneAlarm Probleme macht.

    In welchem Forum? Hier oder bei MSDN oder bei CheckPoint?

    Habs mit ZoneAlarm auch mal unter Windows7-32-Bit versucht. Da funktioniert es wieder. Und mit kleineren Paketen hab ich es schon mal versucht, das klappt auch. Nur die genaue Grenze weiß ich nicht.

    Es kommt scheinbar alles zusammen. ZoneAlarm bei Win7-64-Bit, zu große Pakete und Sender/Empfänger lokal auf demselben Rechner. Da glaub ich auch dass das nicht oft vorkommt bzw. auffällt.

    So oder so, ich werds mal an CheckPoint melden.

    Danke!



  • SchlechterInformatiker schrieb:

    hustbaer schrieb:

    Du kannst einen "Known Issues" Bereich im Readme machen, und da reinschreiben dass das Dinge mit Version so-und-so von ZoneAlarm Probleme macht.

    In welchem Forum? Hier oder bei MSDN oder bei CheckPoint?

    Forum?
    Readme.txt, nix Forum 😃



  • Achso in der Readme.txt. Hab ich überlesen 😉


Anmelden zum Antworten