Problems with recieving multiple packets at once.

Started by
9 comments, last by ChaosPhoenix 19 years, 6 months ago
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; 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()?
Advertisement
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".
enum Bool { True, False, FileNotFound };
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.
Are the calls to recv() located within worker threads?

Kuphryn
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.
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?

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.
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:/
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
Armand -------------------------It is a good day to code.
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.

This topic is closed to new replies.

Advertisement