I have a Java TCP game server, I use java.net.ServerSocket
and everything runs just fine, but recently my ISP did a some kind of an upgrade, where, if you send two packets very fast for the same TCP connexion, they close it by force.
This is why a lot of my players are disconnected randomly when there's a lot of traffic in game (when there is a lot of chance that the server will send 2 packets at same time for the same person)
Here is an example of what I mean: If I do something like this, my ISP will close the connexion for no reason to both client and server side:
tcpOut.print("Hello.");
tcpOut.flush();
tcpOut.print("How are you?");
tcpOut.flush();
But it will work just fine if i do something like this:
tcpOut.print("Hello.");
tcpOut.flush();
Thread.sleep(200);
tcpOut.print("How are you?");
tcpOut.flush();
Or this:
tcpOut.print("Hello.");
tcpOut.print("How are you?");
tcpOut.flush();
This only started a couple of weeks ago when they (the ISP) did some changes to the service and the network. I noticed using Wireshark that you have to have at least ~150ms time between two packets for same TCP connexion or else it will close.
1)Do you guys know what is this called ? does is it even have a name ? Is it legal ?
Now I have to re-write my game server knowing that I use a method called: send(PrintWriter out, String packetData);
2)Is there any easy solution to ask java to buffer the data before it sends it to clients ? Or wait 150ms before each sending without having to rewrite the whole thing ? I did some googling but I can't find anything that deals with this problem. Any tips or information to help about this would be really appreciated, btw speed optimisation is very crucial. Thank you.
You may create a Writer
wrapper implementation to keep track of last flush
call timestamp. A quick implementation is to add a wait call to honor the 150 ms delay between two consecutive flushes.
public class ControlledFlushWriter extends Writer {
private long enforcedDelay = 150;
private long lastFlush = 0;
private Writer delegated;
public ControlledFlushWriter(Writer writer, long flushDelay) {
this.delegated = writer:
this.enforcedDelay = flushDelay;
}
/* simple delegation for other abstract methods... */
public void flush() {
long now = System.currentTimeMillis();
if (now < lastFlush + enforcedDelay) {
try {
Thread.sleep(lastFlush + enforcedDelay - now);
} catch (InterruptedException e) {
// probably prefer to give up flushing
// instead of risking a connection reset !
return;
}
}
lastFlush = System.currentTimeMillis();
this.delegated.flush();
}
}
It now should be enough to wrap your existing PrintWriter
with this ControlledFlushWriter
to work-around your ISP QoS without re-writing all your application.
After all, it sounds reasonable to prevent a connection to flag any of its packet as urgent... In such a condition, it is difficult to implement a fair QoS link sharing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With