Overflowing Buffers!

Started by
8 comments, last by Xanather 11 years, 6 months ago
Context (if it matters): Creating a game networking system using C# and .net's TcpClient/NetworkStream (no network library).

The client and server programs both have two buffers, the upload buffer and the download buffer, both are 64kb in size (I am talking about application buffers here).

The download buffer is used for downloading available bytes on the network stream at the start of every game tick.
The upload buffer is used for sending all messages (within that game tick) at the end of every game tick.

Current problems I am experiencing is how to handle this all:

  • Currently the download buffer can easily overflow, if available bytes available on the stream are greater than the byte buffer (64kb) minus the current data stored in the byte buffer (due to possibly previous half messages received in previous ticks) then the buffer obviously overflows.
  • Another problem I have is the upload buffer, throughout a game tick messages are added to the upload buffer; which is then sent at the end of the game tick. If massive messages are sent within one game tick (greater than 64kb) then the upload buffer overflows.

Question(s): How can I handle the two dot points above? is overflowing buffers normal? (I remember playing gmod a few times and got the buffer overflow errors). Do I even need a upload buffer? should I just write directly to the stream once a message has been created during a tick?

Right now whenever I try sending even one chunk (containing tile data) from the server -> client the upload buffer overflows on the server and the download buffer would overflow on the client. I solved the problem by forcefully making the server send the upload buffer multiple times before the end of a game tick and making the client download the chunk over more than 1 tick (by checking if the buffer is close to overflowing when reading 256 byte increments from the stream during a tick). But I feel like I hackishly solved the problem and my code is no longer consistent.

All replies are appreciated, thanks.

Edit: I would read available bytes from the stream instantaneously as they arrive/are sent but each client is not assigned a thread. Also: sorry if I am asking too much :(
Advertisement
Use bigger buffer or use dynamic buffer which increases everytime it overflows. Eventually it'll reach max size when it stops overflowing, however it might end up eating whole RAM if you have bug somewhere.
@Ripiz. Ok, I will try change the size to 1MB (which will allow for bits of world chunks). There is no other performance decrease in doing this except for more RAM usage right?
Using a larger buffer uses more RAM, and, at the extreme, may cause heap fragmentation (you're a while away from that danger yet I think.)

The other problem with big buffers is that nothing else can be sent at the same time on that same stream. If you're using a single TCP connection for all game data, that means all chat, world movement, friend requests, and other such information is blocked by transferring the large amount of data. You might be better off defining a protocol that first establishes a chunk ("define chunk 123 to have size 800 kB") and then sends pieces of that chunk as packets ("here's the data for offset 324,000 size 2,000 for chunk 123") and finally, when all pieces are sent, sends the "use chunk" message.
enum Bool { True, False, FileNotFound };
That makes sense, your saying to use a complete different TCP stream (different port) or use UDP for tile chucks? Or during when the connection is being established between the server/client (handshakes etc..)?
You can use another TCP stream -- you can even use HTTP for larger downloads; HTTP is a fine bulk data transfer protocol with lots of good infrastructure available.

What I was actually suggesting was that you time-slice the existing TCP stream, though. If you already have "packet types" over TCP (which I presume you do, else you're going to want to add that,) then you can define a number of smaller packets, which, when put together, transfer the entire large chunk of data. The benefit is that you can send different kinds of packets in between each fragment of the big file, so the entire connection doesn't appear to "freeze" while downloading one big thing.
enum Bool { True, False, FileNotFound };
Yes I do have prefixed messages types (byte) and message lengths (short).
Well, that makes sense, so just send parts of the chunk each tick? (and each tick chunk could have just one x row of the whole chunk?).

Also is there any point to having a application upload buffer? Should I write directly to the stream every time something happens (even if its just a chat message being sent)? I feel having the program upload everything in one tick is better to do than write several times (if not 20+ times) per tick.

thanks for your help hplus.
Yes, it's usually better to buffer all outgoing messages and send them in one fell swoop when the "tick time" comes. If you ever change to UDP, that's a requirement. For TCP, the OS will do some of that buffering for you, if you do not turn off Nagling (i e, do not turn on TCP_NODELAY.)
enum Bool { True, False, FileNotFound };
Ahhh, right, I have turned that off xD (in order to lower latency), so I'm going to stick to what I have.

thanks again smile.png
Done! Implemented it successfully (over several ticks) and it works like a charm with only 256kb application buffers :D.

This topic is closed to new replies.

Advertisement