NetConnection::windowFull() - returning true
by Fabian Holmberg · in Torque Game Engine · 04/18/2005 (3:22 am) · 17 replies
I am implementing my proof of concept based on TNL. Over the last few days I seem to have randomly been encountering this function call:
This is called from NetInterface and returns true when (to my understanding) there was a buffer overflow in terms of how much data can be sent accross the wire. However, I only seem to get this when I run my app in debug (F5) mode in Visual Studio (?). When I execute the exact same app (Ctrl + F5), I do not appear to get this problem.
I have been plagued by this error over the last few days as its inconsistant and have even tried to limit the amount of packets dished out by the server using a timer but it has not helped - i still get a return true after a certain amount of time in debug mode.
Is there any other cause that would make
return true then please let me know as I only have a day or two left on my proof of concept and am trying to understand this function occasionally gives me a true result after a certain amount of time...
NetConnection::windowFull()
This is called from NetInterface and returns true when (to my understanding) there was a buffer overflow in terms of how much data can be sent accross the wire. However, I only seem to get this when I run my app in debug (F5) mode in Visual Studio (?). When I execute the exact same app (Ctrl + F5), I do not appear to get this problem.
I have been plagued by this error over the last few days as its inconsistant and have even tried to limit the amount of packets dished out by the server using a timer but it has not helped - i still get a return true after a certain amount of time in debug mode.
Is there any other cause that would make
NetConnection::windowFull()
return true then please let me know as I only have a day or two left on my proof of concept and am trying to understand this function occasionally gives me a true result after a certain amount of time...
About the author
#2
What would you mean by "eating" packets? You mean preventing them from being sent?
04/19/2005 (3:07 am)
Yes that makes sense, as soon as one application was paused (or stopped in debug mode), the other (which was still executing) would immediately have its windowfull since its not getting any response from its accumilated sendack packets.What would you mean by "eating" packets? You mean preventing them from being sent?
#3
04/20/2005 (12:56 am)
Or preventing them from being delivered, yes.
#4
So in this respect, I have overridden the
I presume that so long as the connectionToServer->hasUnackedSentPackets() is taken into account, i should not need to send unecessary data accross the wire. Please correct me if I am wrong on this.
04/20/2005 (8:18 pm)
Actually, what i am trying to do is simply get control over how much data is actually sent. if the game state has not changed or a client has not moved, i dont want that client to send unecessary updates to the server. So in this respect, I have overridden the
isDataToTransmit()function to "eat" packets. It now returns a member boolean variable which i preset to a value based on if the client moved or not as examplified below:
if(!connectionToServer->hasUnackedSentPackets() && !StateHasChanged()) // This will make isDataToTransmit() return false in NetConnection connectionToServer->SetHasDataToTransmit(false); else // This will make isDataToTransmit() return true in NetConnection connectionToServer->SetHasDataToTransmit(true);
I presume that so long as the connectionToServer->hasUnackedSentPackets() is taken into account, i should not need to send unecessary data accross the wire. Please correct me if I am wrong on this.
#5
04/21/2005 (11:10 am)
But TNL already does this, if you have adaptive mode on... Why reimplement? Some minimal "packet overhead" is needed for the acking to work out properly.
#6
I actually have tried using isAdaptive() a few days ago, and NetConnection::windowFull() started screaming out true in no time. My understanding is that isAdaptive() should be set to true if you want to maximise throughput on a connection, as implicitly TNL has a timer to limit thruput on a connection, if isAdaptive() is set to false.
Are you suggesting that if I intend to dynamically modify isDataToTransmit() as per my abovementioned example, I should have adaptive mode on? I realize that ackpackets need to be sent which was why I included !hasUnackedSentPackets() in my condition. Like i said, the thing clogged up in no time when i used isAdaptive...
04/21/2005 (7:03 pm)
The problem with my implementation is that I do not use ghosting (we are currently not allowed to do so). Instead I brutally send out packets at every frame (from client to server and vice versa). This means that the client sends his position / state update at every frame to the server, regardless of if the position / state has changed or not.I actually have tried using isAdaptive() a few days ago, and NetConnection::windowFull() started screaming out true in no time. My understanding is that isAdaptive() should be set to true if you want to maximise throughput on a connection, as implicitly TNL has a timer to limit thruput on a connection, if isAdaptive() is set to false.
Are you suggesting that if I intend to dynamically modify isDataToTransmit() as per my abovementioned example, I should have adaptive mode on? I realize that ackpackets need to be sent which was why I included !hasUnackedSentPackets() in my condition. Like i said, the thing clogged up in no time when i used isAdaptive...
#7
Adaptive means that it will adaptively use bandwidth - using less if appropriate, or more if needed. It's not heavily tested, but it should work just fine. I believe you have to set the flag in your connection creation parameters. isAdaptive() is just a helper function to query the state of that parameter, used almost exclusively interally. You shouldn't have to modify any code to make an adaptive connection.
04/21/2005 (11:38 pm)
The acking I refer to has nothing to do with ghosting. It's part of the low level packet protocol.Adaptive means that it will adaptively use bandwidth - using less if appropriate, or more if needed. It's not heavily tested, but it should work just fine. I believe you have to set the flag in your connection creation parameters. isAdaptive() is just a helper function to query the state of that parameter, used almost exclusively interally. You shouldn't have to modify any code to make an adaptive connection.
#8
takes care of this. The problem when I turned this on was that all hell broke loose in terms of packet sending. I was getting an overflow quite quickly which makes sense as:
You said you have not done much testing on this, correct?
04/23/2005 (5:47 am)
Actually the:void NetConnection::setIsAdaptive()
takes care of this. The problem when I turned this on was that all hell broke loose in terms of packet sending. I was getting an overflow quite quickly which makes sense as:
Quote:
By default NetConnection operates with a fixed rate protocol - that is, it sends a packet every few milliseconds, based on some configuration parameters. However, it is possible to use an adaptive rate protocol that attempts to maximize thoroughput over the connection.
You said you have not done much testing on this, correct?
#9
04/24/2005 (6:06 pm)
We did enough that it worked for the sample applications.
#10
What was strange though was that as soon as the game started running again on both ends, both players were in total sync with regard to each others position, despite the window being continuously full on the server side. Position data has to be sent accross the wire so if the packets are out of sync, how is it that the positions are allways in sync on both ends?
We send positional data accross the wire so as soon as the window is full on either side, the players positions are also out of sync as well, unlike ZAP. Would be great if you can point me in the right direction as to how you implemented this getaround in ZAP...
05/18/2005 (1:45 am)
I decided to give ZAP a test by running a client/server then a client who joined that game thus having two players in total. In debug mode, I intentionally froze the second player (by placing a breakpoint in the code). This triggered a windowfull on the server side, which was obviously waiting for packets.What was strange though was that as soon as the game started running again on both ends, both players were in total sync with regard to each others position, despite the window being continuously full on the server side. Position data has to be sent accross the wire so if the packets are out of sync, how is it that the positions are allways in sync on both ends?
We send positional data accross the wire so as soon as the window is full on either side, the players positions are also out of sync as well, unlike ZAP. Would be great if you can point me in the right direction as to how you implemented this getaround in ZAP...
#11
TNL has a window of up to (by default) 32 packets. What this means is that either side of a connection can send up to 32 packets to the other side before getting an ack from the other side - so as soon as you hit the breakpoint on the client, the server will send the 32 packets (one on every fixed period time interval) and then the window will be full so it will stop sending packets, except for ping packets.
Once the client is allowed to continue, it will receive all the packets from the server, and the next packet it sends to the server will contain acks for all the packets it received. This will advance the window on the server so that it is no longer full, and the server will again send packets. So the "window being continuously full" on the server side doesn't happen, and the client and server go along on their merry way.
Which is why I couldn't figure out why you were having the problem in the first place...
05/18/2005 (8:48 am)
Hey Fabian,TNL has a window of up to (by default) 32 packets. What this means is that either side of a connection can send up to 32 packets to the other side before getting an ack from the other side - so as soon as you hit the breakpoint on the client, the server will send the 32 packets (one on every fixed period time interval) and then the window will be full so it will stop sending packets, except for ping packets.
Once the client is allowed to continue, it will receive all the packets from the server, and the next packet it sends to the server will contain acks for all the packets it received. This will advance the window on the server so that it is no longer full, and the server will again send packets. So the "window being continuously full" on the server side doesn't happen, and the client and server go along on their merry way.
Which is why I couldn't figure out why you were having the problem in the first place...
#12
How does it recieve all the outstanding packets from the server in a single go on your end? Thats what clearly does not seem to happen on our side. It seems that once the window is full, its allways full (on both ends). It will proceed to permanently trail 30+ packets behind and never recieve them all in one go. That gap only increases over time, so for example, after a few minutes, it can take 30 seconds or more for the move to actually be recieved on the other end...
There has got to be something in my settings that is influencing this - I am using the following values on both the client and the server.
According to the abovementioned settings, the client can only recieve one packet every 96 MS. As per this logic, its normal that it does not recieve all outstanding packets in a single go... The only alternative I can think of is manually altering the recieve parameters dynamically, as soon as the window gets full... I saw that there were some adaptive connections in your ZAP program, despite the fact that you strongly disrecommend us from using it. Maybe that could hold the key to recieving all packets in a single go...
05/18/2005 (7:56 pm)
Quote:Once the client is allowed to continue, it will receive all the packets from the server, and the next packet it sends to the server will contain acks for all the packets it received.
How does it recieve all the outstanding packets from the server in a single go on your end? Thats what clearly does not seem to happen on our side. It seems that once the window is full, its allways full (on both ends). It will proceed to permanently trail 30+ packets behind and never recieve them all in one go. That gap only increases over time, so for example, after a few minutes, it can take 30 seconds or more for the move to actually be recieved on the other end...
There has got to be something in my settings that is influencing this - I am using the following values on both the client and the server.
setFixedRateParameters(96, 96, 5000, 5000);
According to the abovementioned settings, the client can only recieve one packet every 96 MS. As per this logic, its normal that it does not recieve all outstanding packets in a single go... The only alternative I can think of is manually altering the recieve parameters dynamically, as soon as the window gets full... I saw that there were some adaptive connections in your ZAP program, despite the fact that you strongly disrecommend us from using it. Maybe that could hold the key to recieving all packets in a single go...
#13
05/18/2005 (10:48 pm)
ZAP uses the adaptive connection only for communication with the master server -- not for game traffic. As for the one packet every 96 ms, that's the send period -- the server will only send one packet once every 96 ms, but they will just end up in a queue on the client, all to be processed the next time packets are read from the socket. Are you doing something funky at the event/RPC layer that would add additional delay?
#14
I am currently not using any RPC's in my framework - as for the eventconnection layer, my subclasses call eventConnections read/writePacket(...) in their respective read/writePacket functions. Beyond that, nothing on the network front...
Where exactly are the packets queued on the client while its put on hold? If its on a winsock level, then its beyond my control, but if its somewhere in Netconnection, then maybe I can intervene and extract them all promptly...
05/19/2005 (1:56 am)
Hey Mark,I am currently not using any RPC's in my framework - as for the eventconnection layer, my subclasses call eventConnections read/writePacket(...) in their respective read/writePacket functions. Beyond that, nothing on the network front...
Where exactly are the packets queued on the client while its put on hold? If its on a winsock level, then its beyond my control, but if its somewhere in Netconnection, then maybe I can intervene and extract them all promptly...
#15
05/20/2005 (3:09 pm)
There is no queuing of the packets in TNL. When you pause in the debugger, any packets received will be queued in the socket's read buffer until the application has cycles to read them out. All the packets will be read by the NetInterface::checkIncomingPackets function as soon as it is called.
#16
05/23/2005 (11:17 pm)
Ok - thanks for that. At least I know it happens on a socket level. Will have to make comparisons as to why ZAP is doing what it should and my application is not.
#17
05/26/2005 (1:40 am)
Just to inform everyone - our project has been put on hold for 4 months so you wont be hearing from me during that time. Hope to be able to resume it after that... Until then - cheers!
Associate Ben Garney
bool NetConnection::windowFull() { if(mLastSendSeq - mHighestAckedSeq >= (MaxPacketWindowSize - 2)) return true; if(isAdaptive()) return mLastSendSeq - mHighestAckedSeq >= cwnd; return false; }If the distance between highest acked packet and the last sent packet is more than the window size, less two, then the window is full.
If it is an adaptive connection, then the dynamic throttling value (cwnd) is also checked as a window size limiter.
Otherwise the window is not full.
You may get full windows if one end of the connection freezes up (perhaps due to a debug activity?) for a certain amount of time. Or, if you're using adaptive networking, you might be getting throttled down too quickly.
The window will clear when more acks are received.
Are you doing anything that might be "eating" packets? Or anything that might cause one end of the connection (opposite to that which is getting the full windows) to freeze for any appreciable length of time?