I need some help about optimisation. I am trying to improve this open-source game server made with JAVA. Each player has its own thread, and each thread goes something like this:
BufferedReader _in = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
String packet = "";
char charCur[] = new char[1];
while(_in.read(charCur, 0, 1)!=-1)
{
if (charCur[0] != '\u0000' && charCur[0] != '\n' && charCur[0] != '\r')
{
packet += charCur[0];
}else if(!packet.isEmpty())
{
parsePlayerPacket(packet);
packet = "";
}
}
I have been told so many times that this code is stupid, and I agree because when profiling it I see that reading each byte and appending it using packet += ""
is just stupid and slow.
I want to improve this but I don't know how.. I'm sure I can find something, but I'm afraid it will be even slower than this, because I have to split packets based on the '\u0000
', '\n'
, or '\r'
to parse them. And I know that splitting 3 times is verry slow.
Can someone give me an idea? Or a piece of code for this? It will make my day.
If you're going to explain, please, please use verry simple words, with code examples, I'm just a JAVA beginner. Thank's
Perhaps you should look into the readLine() method of BufferedReader. Looks like you're reading Strings, calling BufferedReader.readLine() gives you the next line (sans the newline/linefeed).
Something like this:
String packet = _in.readLine();
while(packet!=null) {
parsePlayerPacket(packet);
packet = _in.readLine();
}
Just like you're implementation, readLine() will block until either the stream is closed or there's a newline/linefeed.
EDIT: yeah, this isn't going to split '\0'. You're best bet is probably a PushbackReader, read in some buffer of chars (like David Oliván Ubieto suggests)
PushbackReader _in = new PushbackReader(new InputStreamReader(_socket.getInputStream()));
StringBuilder packet = new StringBuilder();
char[] buffer = new char[1024];
// read in as much as we can
int bytesRead = _in.read(buffer);
while(bytesRead > 0) {
boolean process = false;
int index = 0;
// see if what we've read contains a delimiter
for(index = 0;index<bytesRead;index++) {
if(buffer[index]=='\n' ||
buffer[index]=='\r' ||
buffer[index]=='\u0000') {
process = true;
break;
}
}
if(process) {
// got a delimiter, process entire packet and push back the stuff we don't care about
_in.unread(buffer,index+1,bytesRead-(index+1)); // we don't want to push back our delimiter
packet.append(buffer,0,index);
parsePlayerPacket(packet);
packet = new StringBuilder();
}
else {
// no delimiter, append to current packet and read some more
packet.append(buffer,0,bytesRead);
}
bytesRead = _in.read(buffer);
}
I didn't debug that, but you get the idea.
Note that using String.split('\u0000') has the problem where a packet ending with '\u0000' won't get processed until a newline/linefeed is sent across the stream. Since you're writing some kind of game, I assume it's important to process an incoming packet as soon as you get it.