Sign in to follow this  
ChaosPhoenix

Problems with recieving multiple packets at once.

Recommended Posts

ChaosPhoenix    242
My server works correctly when users log in one at a time, select from a list of games and then proceed to wait for other players to join. However, if multiple users select a game at the same time then it seems some of the packets sent end up missing. Here's a bit of my server code to get you an idea of how I'm doing my packet processing(This is using WSAAsyncSocket btw)
	ConnectionNode* traverse = 0;
	// Time for a network event!
	switch(GETNETWORKEVENT(msg))
	{
		// Something needs to be read.
		case FD_READ:
		{	
			// Find our Hash code for our socket
			int Code = (int)HASHCODE(wSocket);
			// Go through the table and find the right bucket.
			for(traverse = pTable[Code]; traverse; traverse = traverse->Next)
			{
				// Found the appropriate bucket.
				if(traverse->connection == wSocket)
				{
					// Clear the receive buffer.
					memset(&recvBuffer[0], 0, 1024);
					// Get all pending data.
					recv(wSocket, (char*)&recvBuffer[0], 1024, NULL);
					// What packet type?
					switch(recvBuffer[0])
					{
                                          .. Packets handled here.
                                        }

				
				}

				break;
			}
			/*if(traverse == NULL)
			{
					char deadBuffer;
					while((recv(wSocket, &deadBuffer, 1, NULL)) > 0) { };
			}*/
			break;
		}
// End of packet handling for reading.

does recv() have issues with packets coming from multiple sources at the same time? Do I need to be using anything special since I'm using WSAAsyncSelect()?

Share this post


Link to post
Share on other sites
hplus0603    11356
If you are using TCP, it's quite possible that your recv() reads data for more than one packet in the same go (as long as those packets were all sent by the same client). It seems likely that you're using TCP, because you're not using recvfrom(), and you have more than one socket open.

Note that, if you're unlucky, you may receive one-and-a-half of a packet, which means that you'll be very confused when the next half shows up sometimes later.

The typical fix for this problem is to prefix each packet with a length; one or two bytes on the wire. Receiving then turns into "read length" followed by "read that many bytes".

Share this post


Link to post
Share on other sites
ChaosPhoenix    242
Quote:
Original post by hplus0603
If you are using TCP, it's quite possible that your recv() reads data for more than one packet in the same go (as long as those packets were all sent by the same client). It seems likely that you're using TCP, because you're not using recvfrom(), and you have more than one socket open.

Note that, if you're unlucky, you may receive one-and-a-half of a packet, which means that you'll be very confused when the next half shows up sometimes later.

The typical fix for this problem is to prefix each packet with a length; one or two bytes on the wire. Receiving then turns into "read length" followed by "read that many bytes".


I am using TCP, sorry for not mentioning that early.

Each client only sends 1 of the packets that seem to show up missing. None of them are sending multiple packets at the same time, it's just all the clients sending information to the server before it can apparently deal with all of them. recv() combining packets is what worries me as well, if it is then I'll just have to find a way to deal with that.

Share this post


Link to post
Share on other sites
ChaosPhoenix    242
Quote:
Original post by kuphryn
Are the calls to recv() located within worker threads?

Kuphryn


There is no multithreading on the server(it's got a max of 4 people right now) so no.

Share this post


Link to post
Share on other sites
Soul    162
how are you checking for a full packet, it looks like you just put whatever is received into the begining of the buffer, if you only get half a packet on one recv,then the second half arrives you overwrite the first half?

Share this post


Link to post
Share on other sites
ChaosPhoenix    242
Quote:
Original post by Soul
how are you checking for a full packet, it looks like you just put whatever is received into the begining of the buffer, if you only get half a packet on one recv,then the second half arrives you overwrite the first half?


The packets are extremely small. The largest being 16 bytes I believe, I was hoping I wouldn't have to deal with recv() giving me half packets since they are so tiny.

Share this post


Link to post
Share on other sites
ChaosPhoenix    242
This seems to be what's killing me and I can't seem to find out why. After this call(if it's sending to multiple clients) it's like I fail to recieve any more FD_READ msg's.


ConnectionNode* traverse2 = 0;
for(int a = 0; a < EXPECTED_PLAYER_COUNT; a++)
{
for(traverse2 = this->pInstance->pTable[a]; traverse2; traverse2 = traverse2->Next)
{
if(traverse2->iGameState == GAMEA)
{
memset(&buffer[0], 0, 16);
buffer[0] = (unsigned char)GAMESTATE;
memcpy(&buffer[1], &iGameState, sizeof(int));
memcpy(&buffer[5], &traverse2->iPlayerNum, sizeof(int));
int nret = send(traverse2->connection, (char*)&buffer[0], 16, 0);

}
}




Hope this helps you guys narrow down what I am doing wrong.

EDIT: Sorry for the code being right aligned:/

Share this post


Link to post
Share on other sites
Armand    164
As long as you keep your packes small (< 1024 bytes I think, Its the "atomic length") then you wont get partial packets.

Id say what is happening (which has been said) is that your recv is reading more then one packet at a time. So its more of a protocall problem. Not tcp, but the struct of data your sending and trying to read.

Do you have the size of how many bytes your trying to send/read?
{asuming no}

There are two ways around this.

================

One is to restructor your data.
E.g
Packet Header : Fixed size containing the length of any varible length data.
Packet Detail : the same lenght as specifiyed in the header

After you've done this, you read the fixed length Header.
Then if you need to you read the variable length detail, as you know how long it is, then your not going to read some part of the next packet.

================

The second is to rework your code at the point of "What packet type?".
You would need to change it to a read and consume method.

I'm assuming by your descriptin of the problem, your sending small strings to the server. Key words if you will.

What you would need to do, is read the buffer char by char until you get a compleate Key word. Action that key word and remove it from the buffer.
Anything leftover from that client would have to be saved until you get more data from that client, while your key words are small, a lot of them are not, you might hit a buffer edge and get half a word.

======================

Does this help?

Armand

Share this post


Link to post
Share on other sites
ChaosPhoenix    242
Quote:
Original post by Armand
As long as you keep your packes small (< 1024 bytes I think, Its the "atomic length") then you wont get partial packets.

Id say what is happening (which has been said) is that your recv is reading more then one packet at a time. So its more of a protocall problem. Not tcp, but the struct of data your sending and trying to read.

Do you have the size of how many bytes your trying to send/read?
{asuming no}

There are two ways around this.

================

One is to restructor your data.
E.g
Packet Header : Fixed size containing the length of any varible length data.
Packet Detail : the same lenght as specifiyed in the header

After you've done this, you read the fixed length Header.
Then if you need to you read the variable length detail, as you know how long it is, then your not going to read some part of the next packet.

================

The second is to rework your code at the point of "What packet type?".
You would need to change it to a read and consume method.

I'm assuming by your descriptin of the problem, your sending small strings to the server. Key words if you will.

What you would need to do, is read the buffer char by char until you get a compleate Key word. Action that key word and remove it from the buffer.
Anything leftover from that client would have to be saved until you get more data from that client, while your key words are small, a lot of them are not, you might hit a buffer edge and get half a word.

======================

Does this help?

Armand


Yea, the next server I write will use that structure of "here's a buffer of junk, find out what is in it, sort, and deal with each packet appropriately".

My way around the recv() problem was that there is a chain each client goes through in order to update the server(I know it's hideous, just bare with me, if I wasn't under a deadline for this I would rewrite the entire thing).

PC1 tells Server it's time for an update.
Server tells PC1 okay and ask's for it's information.
Once the server recieves the information it sends the next request to the next player in the line(there are 4 total) and waits for their reply before asking the next player in line.

It's impossible for recv() to be getting multiple packets at that point. It should only be getting 1 at every request the server makes. The problem is the server isn't getting any FD_READ messages AT ALL if there are 2+ people connected. 1 Person works great, 2 or more and I get no FD_READs after the code I posted above so the information chain is never started.

Share this post


Link to post
Share on other sites
ChaosPhoenix    242
I've played with it alittle more and I'm even more lost.

Lets say for example 2 players are connected.

Server intializes both players and sends them their correct state.

Game ends and it's time for scores.

If 1st player tries to send the score it won't ever make it to the server(although the send() fuction says the data was sent without error) because the server will never generate an FD_READ message for it.

If 2nd player(or the last player to recieve information from the server) sends information then it will send correctly and the FD_READ message will be generated.

Again, this is using WSAAsyncSelect() enabled sockets but I thought that a recv/send message on whatever socket would still generate the appropriate message on the server and that the wParam could be used to find what socket generated the event.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this