Daten an IP senden



  • Zu den "Warum's": Das habe ich weiter oben schon beschrieben, ich versuche so, den Programmablauf von Client und Server synchron zu halten. Ich muss doch, wenn ich in einem Programm die send()-Funktion aufrufe, dafür sorgen, dass irgendwo jemand zuhört, oder? Die Daten sollen ja nicht verloren gehen.

    Aber es ist schonmal beruhigend, dass nicht die Funktionen an der Programmgeschwindigkeit schuld sind, sondern ich. Ich hänge ein wenig Quelltext an, aber ohne jede Variable zu erklären usw. - es geht ja nur um send() und recv().

    if(server == 0)			//Client wartet auf den Startschuss
    	{	while(connection_buffer[0] != -1)
    		{	connection_buffer[0] = 0;
    			recv(con , connection_buffer , 1 , 0);
    		}
    		connection_buffer[0] = 0;
    	}
    	while (!quit)
    	{	if (PeekMessage(& msg , NULL , 0 , 0 , PM_REMOVE))
    		{	if (msg.message == WM_QUIT)
    				quit = 1;
    			else
    			{	TranslateMessage(& msg);
    				DispatchMessage(& msg);
    			}
    		}
    		if(ball_to_reset && server != 0)
    		{	ballreset(ballx , bally , ballv);
    			ball_to_reset = 0;
    		}
    		time_now = _time_count();  //Zeit wird gemessen
    		if(server == 1)
    			con_data = NULL;
    		passive = 127;
    		memset(connection_buffer , 0 , 10);
    		if(server == 1)
    		{	connection_buffer[0] = -1;
    			for(i = 0 ; i < 10 && send(con , connection_buffer , 1 , 0) != 1 ; i ++);
    			for(i = 0 ; i < 10 && recv(con , connection_buffer , 2 , 0) != 2 ; i ++);
    		}
    
    		//2-Byte-Block : Steuerdaten des Clienten
    		//90-Byte-Block: Spieldaten des Servers
    		//1-Byte-Block : Synchronisationsdaten
    
    		if(!ball_redrawn)
    			time_buffer = time_now;
    		if(server == -1)
    		{	player_action(player1x , player1y , ballx , bally , ballv , 0);	//1 = senden, 0 = empfangen
    			//player_action(NULL , NULL , ballx , bally , ballv , 0);
    			//npc_rethink(player1x , player1y , ballx[0] , bally[0] , ballv);
    			npc_rethink(player2x , player2y , ballx[0] , bally[0] , ballv);
    		}
    		if(server == 0)
    		{	client_action(& passive);
    			connection_buffer[0] = passive;
    			for(i = 0 ; i < 10 && send(con , connection_buffer , 2 , 0) != 2 ; i ++);
    			for(i = 0 ; i < 10 && recv(con , con_data , con_data_length , 0) != con_data_length ; i ++);
    		}
    		if(!ball_redrawn && server != 0)
    			ball_repositioning(ballx , bally , ballv , player1x , player1y , player2x , player2y);
    		if(server == 1)
    		{	passive = connection_buffer[0];
    			player_action(player1x , player1y , ballx , bally , ballv , 0);
    			player_action(player2x , player2y , ballx , bally , ballv , passive);
    			//ab hier geht's nicht mehr
    			con_data = _prepare_data(ballx , bally , ballv , player1x , player1y  , player2x , player2y , pointsP1_i , pointsP2_i , special ,
    					special_colour , ball_redrawn , sbuffer);
    			for(i = 0 ; i < 10 && send(con , con_data , con_data_length , 0) != con_data_length ; i ++);
    			for(i = 0 ; i < 10 && recv(con , connection_buffer , 1 , 0) != 1 ; i ++);
    		}
    //...
    

    Soviel muss reichen, man wird wohl auch sehen, worum es geht ;). Das Hängen des Programms wird wohl bei den recv()-Funktionen entstehen, aber ich verstehe nicht, warum das zu so großen Verzögerungen führt. Ein Durchlauf der gezeigten while-Schleife sollte ein paar Millisekunden dauern, so dauert er einige Sekunden.



  • Warum denn zehn mal send/recv ??

    recv(con , connection_buffer , 1 , 0)
    

    liest nur 1 byte...

    wenn du mit blocking sockets arbeitest synchronisierst du ganz automatisch...

    Aber für sowas bräuchte ich den ganzen code...



  • Wie gesagt, die Schleife beginnt und läuft beliebig lang, während dieser Zeit versuche ich, dass beide synchron laufen.

    Die Byte-Zahlen habe ich mit Kommentar versehen. 2 Byte sind Daten vom Clienten, 90 Byte (ok, die Zahl sieht man nicht direkt - es handelt sich um con_data_length) die Server-Daten und dann gibt es noch ein Byte, das dem Clienten sagt, wann die while-Schleife einmal durchlaufen wurde. Alles weitere sind Synchronisierungsversuche.

    Was das Blocken angeht: recv() blockt solange, bis es ein Signal empfängt. Aber dafür muss ich ja dafür sorgen, dass zuerst der Client die recv()-Funktion startet und dann der Server sendet. Damit das gewährleistet ist, habe ich eben diese ganzen recv() und send()-Funktionen eingebaut. Hier mal meine Sockets:

    SOCKET con;
    	SOCKET accept_socket;
    	WSADATA wsa;
    
    	if(server == 0)						//Client
    	{	SOCKADDR_IN saddr;
    		if(WSAStartup(MAKEWORD(2 , 0) , & wsa))			//Socket-Initialisierung
    			quit = 1;
    		con = socket(AF_INET , SOCK_STREAM , 0);
    		if(con==INVALID_SOCKET)
    			quit = 1;
    		saddr.sin_family = AF_INET;
    		saddr.sin_port = htons(12345);					//Welchen Port nehmen?
    		saddr.sin_addr.s_addr = inet_addr(server_ip);
    		saddr.sin_zero[0] = '\0';
    		connect(con , (SOCKADDR*)&saddr , sizeof(SOCKADDR));
    	}
    	if(server == 1)						//Server
    	{	SOCKADDR_IN accaddr;
    		if(WSAStartup(MAKEWORD(2 , 0) , & wsa))			//Socket-Initialisierung
    			quit = 1;
    		accept_socket = socket(AF_INET , SOCK_STREAM , 0);
    		if(accept_socket==INVALID_SOCKET)
    			quit = 1;
    		accaddr.sin_family = AF_INET;
    		accaddr.sin_port = htons(12345);				//Welchen Port nehmen?
    		accaddr.sin_addr.s_addr = ADDR_ANY;
    		accaddr.sin_zero[0] = '\0';
    		bind(accept_socket , (SOCKADDR*)&accaddr , sizeof(SOCKADDR_IN));
    		listen(accept_socket , 10);
    		con = accept(accept_socket , NULL , NULL);
    		if(con==INVALID_SOCKET)
    			quit = 1;
    	}
    


  • aber warum die for schleife ?

    10 clients ? Und wenn weniger beitreten ? Blocken für immer ?



  • Ok, es hat zwar eine Weile gedauert, aber ich habe den Fehler gefunden :).
    Zuersteinmal habe ich meinen Code ein wenig aufgeräumt, war doch mehr oder minder unübersichtlich so ;).
    Die for-Schleife würde nur betreten, wenn etwas beim Übertragen schief gelaufen wäre. Eine der Abbruchbedingungen prüft auf die Datenlänge - das hat zwar ganz gut geklappt, aber deinen Worten habe ich entnommen, dass bei send() und recv() keine Fehler auftreten und ich mir das ganze sparen kann - sie sind jetzt also entfernt.

    Das bisherige Geruckel war das Produkt einiger Kleinigkeiten sowie eines gröberen Fehlers bei der Datenübertragung selbst. Da war ein Pointer im Spiel, wo keiner sein sollte.
    Momentan läuft alles wunderbar, nur kann ich eine winzige Verzögerung zwischen Client und Server beobachten (und es laufen bei auf dem localhost). Gibt es da irgendwelche generellen Tipps? Falls es hilft, hänge ich nochmal meinen etwas aufgeräumten Quelltext an.

    while (!quit)
    {	if (PeekMessage(& msg , NULL , 0 , 0 , PM_REMOVE))
    	{	if (msg.message == WM_QUIT)
    			quit = 1;
    		else
    		{	TranslateMessage(& msg);
    			DispatchMessage(& msg);
    		}
    	}
    	if(ball_to_reset && server != 0)
    	{	ballreset(ballx , bally , ballv);
    		ball_to_reset = 0;
    	}
    	time_now = _time_count();
    	if(server == 1)
    		con_data = NULL;
    	if(!ball_redrawn)
    		time_buffer = time_now;
    	lastsound = 0;
    
    	//1-Byte-Block : Steuerdaten des Clienten
    	//58-Byte-Block: Spieldaten des Servers
    	if(server == 0)
    	{	client_action(& passive);
    		connection_buffer[0] = passive;
    		recv(con , con_data , con_data_length , 0);
    		send(con , connection_buffer , 1 * sizeof(char) , 0);
    		_use_data(ballx , bally , ballv , player1x , player1y , player2x , player2y , con_data , sbuffer);
    		_control_sound();
    		_calculate_pos(player1x , player1y , player2x , player2y , ballx , bally);
    		_correct_points(pointsP1_i , pointsP2_i , pointsP1 , pointsP2);
    		redraw_scenario(player1x , player1y , player2x , player2y , ballx , bally , NULL , hDC);
    	}
    	if(server == 1)
    	{	passive = connection_buffer[0];
    		player_action(player1x , player1y , ballx , bally , ballv , 0);
    		player_action(player2x , player2y , ballx , bally , ballv , passive);
    		connection_buffer[0] = 127;
    		if(!ball_redrawn)
    			ball_repositioning(ballx , bally , ballv , player1x , player1y , player2x , player2y);
    		con_data = _prepare_data(ballx , bally , ballv , player1x , player1y  , player2x , player2y , pointsP1_i , pointsP2_i , special , special_colour , sbuffer);
    		ping_d = _time_count();
    		send(con , con_data , con_data_length , 0);
    		recv(con , connection_buffer , 1 * sizeof(char) , 0);
    		ping = ((_time_count() - ping_d) * 1000) + 0.5;
    		game_delay(_betrag(time_unit - (_time_count() - time_now)));
    		if(!ball_redrawn)
    		{	difficulty_increase_counter = (unsigned int)(time_now - time_at_gamestart) / stepup;
    			ballv[0] += _signum(ballv[0]) * (difficulty_increase_counter * 0.1 * 2 * mov_speed * ball_speed);
    			mov_speed += 0.1 * difficulty_increase_counter * 200 / gamespeed;
    			if(difficulty_increase_counter)
    				time_at_gamestart = time_now;
    		}
    		else
    			if(time_buffer + 3 < _time_count())
    				ball_redrawn = 0;
    		redraw_scenario(player1x , player1y , player2x , player2y , ballx , bally , ballv , hDC);
    	}
    	traffic += con_data_length + 2;
    }
    

    EDIT: Quelltext geändert



  • Release-Build



  • build0r schrieb:

    Release-Build

    Was willst du mir damit sagen? Ich erstelle schon die ganze Zeit Release-Builds, ich weiß gar nicht, wie ich anders Server und Client gleichzeitig laufen lassen soll.

    Ich bin nicht ganz sicher, ob das hierhin passt, aber ich versuch's einfach mal: Kann ich die vom Server gesendeten Daten irgendwie (ohne viel Aufwand) komprimieren? Der momentane Datendurchsatz liegt bei 1,845 KiB pro Sekunde, für ein Spiel so einfach wie meines finde ich das ganz schön viel. Allerdings werden auch ca. 30 mal pro Sekunde Daten gesendet, evt. gibt es da völlig andere Herangehensweisen?



  • Kann ich die vom Server gesendeten Daten irgendwie (ohne viel Aufwand) komprimieren?

    Weniger senden ^^

    1,845 KiB pro Sekunde

    Aber mal im Ernst, z.B. bei 2 Mega Bit pro Sekunde (z.B. per WLAN) wären das bei 30 Durchläufen in der Sekunde 8,5 KB. Passt doch. 😉



  • Äh, der Rechnung kann ich nicht folgen :D. Ich sagte doch: 1845 Byte pro Sekunde - das sind schon alle 30 Durchläufe.
    Der Punkt ist, dass ich im Prinzip nur ein paar wenige Koordinaten übergebe, kaum eine handvoll Variablen. Dafür finde ich das schon recht viel - ein Spiel über Modem wird da eng ;).

    Mein nächstes Problem ist der Kampf gegen den Ping. Bisher habe ich dagegen noch nichts in mein Programm eingebaut, beim Test auf dem Localhost war das natürlich auch unnötig. Aber ich vermute (muss mal wen zum Testen abstellen ;)), dass spätestens ab einem Ping, der größer ist als eine Spielrunde, Probleme auftreten. Und eine Spielrunde liegt momentan bei 30ms. Bei 50ms pro Runde (also auch nur 20 Bildern pro Sekunde) ruckelt das ganze schon.
    Zur besseren Übersicht passe ich den Quelltext oben mal an den aktuellen Stand an.



  • Dann halt 256 KB pro sec. 😃

    ein Spiel über Modem wird da eng

    Du benutzt ein MODEM ??? Also ANALOG ?

    Allerdings werden auch ca. 30 mal pro Sekunde Daten gesendet, evt. gibt es da völlig andere Herangehensweisen?

    Klar. Verwende halt unblocking sockets, oder einen "Empfangs-Thread".
    Dadurch wird die Zeit nicht gewartet, sondern während die Daten noch auf dem Weg sind neue gesendet.

    Dann musst du aber aufpassen, dass dein Spiel nicht "unendlich" schnell läuft; z.B. mit VSync. Sleep ginge auch, ist aber nicht so toll.


Anmelden zum Antworten