Hello, I'm making a game and currently I'm using TCP.
I have a basic client and server setup...
But I have crossed a problem here, as I'm quite a newbie for networking, I'm stuck on something stupid.
1. Currently, my client simply packs de data with sprintf and sends it to the server. Is this Recommended? Is this too bandwidth intensive? Depending on the info the server has to send the same packet a little modified to all the other clients. The client can send info like his position updated, or that he wrote a chat, shot, etc...
2. Sometimes my server receives like 2 or more packets of the same client at the same time, like it receives 48 bytes instead of receiving 4 times 12 bytes (they aren't always 12 bytes). The way I designed the server, it kinda only interpretates the whole recv call, it doesn't care/doesn't know if there is more than 1 packet, that's a problem...
What would be the suggested strategy to solve that, prefix every packet with a lenght in bytes? So I do one recv that reads 1 byte, which contains the lenght of the packet, then read that lenght with recv, repeat the process?
3. If I'm going to adopt the send every packet prefixed with a lenght strategy, as I'm using sprintf, how am I going to certify that the packet lenght is only 1 byte? As the number 323 using sprintf is 3 bytes and not 1...
I hope I've managed to make you guys understand me, thanks a lot!
wildfrog
June 7th, 2007, 01:37 PM
1. Currently, my client simply packs de data with sprintf and sends it to the server. Is this Recommended? Is this too bandwidth intensive? Depending on the info the server has to send the same packet a little modified to all the other clients. The client can send info like his position updated, or that he wrote a chat, shot, etc...There is often an overhead by sending information as 'text' (and not a binary data), but then again you avoid some possible problems. Like byte ordering and the hazzle it is to debug binary streams.
2. Sometimes my server receives like 2 or more packets of the same client at the same time, like it receives 48 bytes instead of receiving 4 times 12 bytes (they aren't always 12 bytes). The way I designed the server, it kinda only interpretates the whole recv call, it doesn't care/doesn't know if there is more than 1 packet, that's a problem...
What would be the suggested strategy to solve that, prefix every packet with a lenght in bytes? So I do one recv that reads 1 byte, which contains the lenght of the packet, then read that lenght with recv, repeat the process?TCP is a stream protocol. There are no individual packets (at least not in the upper parts of the stack).
As you mention, one solution is to prefix each 'message' with a length. But not only are 'messages' merged together, they may also be splitted appart.
In your code you should read 'as much as possible' into a buffer. Then examine the prefixed length, check if you got (atleast) one complete message in the buffer. If a complete message is in there, then extract/parse the message. If there is not a complete message, you'll have to wait for more data to arrive.
3. If I'm going to adopt the send every packet prefixed with a lenght strategy, as I'm using sprintf, how am I going to certify that the packet lenght is only 1 byte? As the number 323 using sprintf is 3 bytes and not 1...
You need to apply some rules. A rule could be that the 3 first letters tells the length of the message (and at the same time say that no messages are more the 999 letters).
- petter
MikeAThon
June 7th, 2007, 01:47 PM
Many game programmers find that TCP is too slow for their purposes, and use UDP instead. TCP has overhead associated with its reliability, and that overhead manifests itself in sometimes-slow transmissions (e.g., Nagle and delayed-ACK are responsible for delays that some consider unacceptable).
UDP is faster but is unreliable. You need to balance the two and make your own decision.
In answer to your questions:
1. It's only bandwidth intensive if you are wasting too many bytes. Only you can answer that, since you are the one who knows the bandwidh you are targetting. Do you need to support dial-up connections? You mention that your "packets" are around 12 bytes long, so, as long as they are being sent at a managable rate even for dial-ups, it's difficult to believe that such small payloads are unduly wasteful of bandwidth.
2. The behavior you are seeing is completely normal for TCP. TCP views data as a simple stream of bytes, and pays no attention to "packets" or any groupings that your program tries to enforce. For this reason, your solution of prefixing a length is a very common one. However, for reasons of efficiency, I would recv() everything that TCP wants to give me in one large-ish buffer (4k to 8k), all at once, so as to move the data out of kernel memory and into user memory as quickly as possible. Parse your data from the user memory buffer. Note that there might be partial receives, i.e., you send 4 times 12 bytes, and the recipient receives 40 (not 48) bytes. The remaining bytes are guaranteed to be received eventually, in subsequent calls to recv().
On the other hand, if you decide to switch to UDP, then this problem disappears. Unlike TCP, UDP is a message-based protocol. The message sent by the sender is received one-for-one by the recipient without any other messages being tacked on to the end. Or the message might not be received at all (since UDP is not reliable).
3. I don't understand your question. Pick a format for your prefix and stick to it at both sender and recipient sides. For example, always use 4 bytes for your prefix, and use a format field in sprintf that always yields in a 4-byte printout (like %04d). Naturally, you would need to confirm (before calling sprintf) that the size of the message is less than (here) 1,000 bytes. Or, alternatively, you could send the 4 bytes that comprise the integer itself, without the need to call sprintf at all.
Incidentally, you might look at game developer sites for more game-focussed advice. A good resource is the "Multiplayer and Networking" section of articles at www.gamedev.net . See http://www.gamedev.net/reference/list.asp?categoryid=30
Mike
Clash
June 7th, 2007, 03:07 PM
Thanks for all the replies guys, it's helping me alot.
I found something called TCP_NODELAY which reduced the lag a lot too.
Anyways, the doubt about the lenght I have is quite stupid, so ok, let's suppose the 3 first letters are the lenght. What if the lenght is 15, so it will be the first 2 bytes, and not the first 3...
An int is 4 bytes, right? So I should be able to send the packet "4294967295" using only 4 bytes and not 10 bytes (4,2,9,4...)
Not that I plan to send anything bigger than 999bytes anyways...
3. I don't understand your question. Pick a format for your prefix and stick to it at both sender and recipient sides. For example, always use 4 bytes for your prefix, and use a format field in sprintf that always yields in a 4-byte printout (like %04d). Naturally, you would need to confirm (before calling sprintf) that the size of the message is less than (here) 1,000 bytes. Or, alternatively, you could send the 4 bytes that comprise the integer itself, without the need to call sprintf at all.
This 4 byte thing is what I don't get... if I use sprintf, the size of the lenght will be 1 bytes if it's 8 or even 3 bytes if it's 238
Right now my packets look like this
"5 7 1 328 257"
5 stands for a player property changed
7 with the player of id 7
1 means it's position changed
328 is the new x position
257 is the new y position
So I'm going to prefix all the packets now, that one should turn to:
"135 7 1 328 257"
or
"0135 7 1 328 257"
I don't get it...
Thanks
MikeAThon
June 7th, 2007, 03:21 PM
Use the second option, i.e., "0135 7 1 328 257".
That way, the first three bytes will always be the length of the remaining bytes in the "message". For example, an 8-byte message would look like "00812 45 78".
At the recipient side, strip off the first three bytes, append a '/0' (for the terminating NULL), and then call atoi() to convert it to a number representing the number of bytes in the message.
With three bytes, your "message" can be up to 999 bytes long. If you never intend to send a message more than 99 bytes, then obviously you can get away with only 2 bytes (not three).
Mike
Clash
June 7th, 2007, 08:06 PM
Thanks Mike!
There is no risk, like if a client disconnects while sending a packet, so it's sent incomplete, kinda messing up the whole server reading, as it'd receive like the lenght of other packet thinking it's actually the packet (of the player that disconnected), right?
Thanks
wildfrog
June 7th, 2007, 08:32 PM
If the client disconnects/hangs while sending data, somewhere in the middle of a message, you would probably get an error message returned from the recv or nothing... In the latter case you could have some kind of timeout saying that if nothing is sent within a second/minute/hour then simply disconnect the client and clean up.
- petter
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.