Advertisement

Sending Structs via WinSock

Started by May 01, 2005 06:49 PM
7 comments, last by TalonSnow 19 years, 9 months ago
Another Problem :) But i am certainily learning and i really appreciate all the help I have received so far! Ok in my game I am now trying to send structs across via Winsock, instead of simple Char's. After looking at the FAQ, I got the server to send one correctly. And the client receives it, however, I am doing something wrong (I think client side after casting the retaining struct as a (char*) As when I go to pull out data, what was 20 before being sent, is pulled out as 0 on the client. I am assuming the stuct on the client is completely empty. Here is code sending struct on server:
bool MessageHandler::SendPlayer(playerType message)
{
	
	int nret = send(client,"Pstruct done#",14,0);		// used to tell client a structure is coming
	Sleep(500);
	nret = send(client,(char const*)&message,sizeof(message),0);	//sending a playerType struct to client
		if (nret == SOCKET_ERROR || nret == 0)
		{
			Sleep (2000);
			int nret = send(client,(char const*)&message,sizeof(message),0);
			if (nret == SOCKET_ERROR || nret == 0)
			{
				WriteError("failed to send message");
				return false;
			}
		}
		else
		{
		}
		return true;
}


playerType is the struct I am trying to send across. Sending the Pstruct first allow my client to know a players structure is coming next, and to go to the function to receive it. Clients Recieve code:
void netReceiveStruct()
{
				int ret = recv(st, (char*)&Player, sizeof(Player), 0);
				if (ret <= 0)
					return;
				receivePlayerStruct = false;
				WriteError("struct received");
				//sake of testing
				char testC[10];
				itoa(Player.moves,testC,10);
				WriteError(testC);
				//
}


Player is also a playerType struct, and is declared as a global. Writing out v alue before being sent moves = 20. When it writes it out after receiving it is 0. Any suggestions? [Edited by - TalonSnow on May 1, 2005 10:03:25 PM]
<=- Talon -=>
So recv() returns 0? recv() only returns 0 is the socket was closed on the other end. So if the server finds that recv() returns 0, then the client closed the socket (with closesocket()).
Advertisement
no recv works fine, its the Player struct that returns 0 when i try to get Moves from the structure received. (look at code if you dont understand what im trying to say :) sometimes I dont explain myself very clearly.
<=- Talon -=>
int nret = send(client,"Pstruct done#",17,0);
That sends "Pstruct done#", the NULL terminator, and 3 bytes of whatever follows the string, which is probably gibberish. I don't know if that's the cause of your problem though.
Also, it's probably a bad idea to send text and structs together, since it's difficult to tell when the string ends (unless you transmit the NULL terminator too).
im not sending them together, after that send it pauses then sends the struct in a seperate send.
thanks for catchign the wrong size on the first message sent though. Fixed it to 14.

so anyone know why my struct is empty?

Do I have to do anything with it after i cast it as a Char* to make it back as a stuct or what?
<=- Talon -=>
The code you posted looks fine. Are any of the other members of the struct zero, or is it just the moves member? And is the moves member the first one in the struct?
Are you sure you read everything out of the socket before you read the struct? All I can suggest is that there's something left in the socket's internal buffer (e.g. the NULL terminator). It's also a really bad idea to try to seperate data in TCP/IP with a Sleep(), since if the client lags or something, it could end reading both parts in one go. I assume (hope [smile]) you're just doing this for testing purposes.

Edit: Something to beware of with sending structs the way you are, is that it won't work properly across different machines (E.g. PC -> Mac), since the byte ordering may be different.
Advertisement
yeah sleep is only there right now in testing it. Once i have it working i will accually change it around and get it more to my likeing, but for now, getting it to work is the problem :)
The moves is in toward the beginning of the struct. here is the struct:
struct playerType{	char*		name;	char*		password;	int			health;	int			moves;	int			rank;	int			score;	int			sector;	int			attack;	int			defense;	int			stealth;	int			endurance;	int			pistol;	int			rifle;	int			heavyWep;	int			explosives;	int			sabotage;	int			medic;	int			engineer;	int			drive;	int			fly;	int			navigation;};


and everything is empty.
<=- Talon -=>
Quote:
it pauses then sends the struct in a seperate send


You realize that, on the receiving end, the pause doesn't matter, right? Because you're using TCP, all data you send gets mashed into a single stream with arbitrary block delineations (that only sometimes will match your send() delineation).

I suggest using packet tokenization, as also recommended in the Forum FAQ. And instead of sending a text for what the command is, just send an int (4 bytes) with an enum value in it.

The code you show for sending sends 14 bytes of text, followed by a struct. The code you show for receiving only receives a struct. Clearly, if you stuff the text data in the beginning of the struct, something will go wrong.

Also, it's not guaranteed that a single call to recv() will be able to fill up all of your Player struct; you may get a fragmented packet where only the first half is there, followed by the second half sometime later.
enum Bool { True, False, FileNotFound };
ok thanks for the helpful guidance. I am still a total beginner when it comes to sockets. I will look up and try to understand about tokenization.

As for the int being enum'd for declaring what is coming, I only have one question.

Would all messages coming in then just get parsed the first 4 bytes and then go into a switch statement to handle what to do with the rest of the data?

Only thing i am confused about on this is, if say I receive the first message containing the int value for a player struct, then the struct itself. Would I then check the size to see if it is all there, and if it is then delete the first 4 bytes from the message and then copy it all into a struct? And if it isn't the full struct, do I just throw it somewhere and append the rest when it comes?
<=- Talon -=>

This topic is closed to new replies.

Advertisement