开发者

An infinite loop somewhere in my code

I have this Java game server that handles up to 3,000 tcp connections, each player, or each tcp connection has its own thread, each thread goes something like this:

public void run()
{
    try
    {
        String packet = "";
        char charCur[] = new char[1];

        while(_in.read(charCur, 0, 1)!=-1 && MainServer.isRunning)
        {
            if (charCur[0] != '\u0000' && charCur[0] != '\n' && charCur[0] != '\r')
            {
                packet += charCur[0];
            }else if(!packet.isEmpty())
            {
                parsePlayerPacket(packet);
                packet = "";
            }
        }

     开发者_如何学编程   kickPlayer();

    }catch(IOException e)
    {
        kickPlayer();
    }catch(Exception e)
    {
        kickPlayer();
    }
    finally
    {
        try{
            kickPlayer();
        }catch(Exception e){};

        MainServer.removeIP(ip);
    }
}

The code runs fine, and I know that each thread for each player is a bad idea, but I'll have too keep it this way for now. The server runs fine on a fast machine (6cor x2, 64bits, 24GB RAM, Windows Server 2003).

But at some point, after about 12 hours of UpTime, the server starts to loop somewhere... I know that because the java process takes 99% of the CPU infinitely until the next reboot. And I'm having hard time to profile the application because I don't want to disturb the players. The profiler I use (visualvm) always end up chashing the server without telling me where's the problem.

Anyways, in that piece of code above I think maybe the problem comes from this:

while(_in.read(charCur, 0, 1)!=-1)

(the _in is a BufferedReader of the client's socket).

Is it possible that _in.read() can return something else infinitely that will keep my code runing and taking 99% of ressources? Is there something wrong with my code? I don't understand everything, I only wrote half of it.


Reading one char at a time is almost as slow as building a String with +=. I wouldn't be able to tell you which is worse. It wouldn't surprise me if a single connection tied an entire core using this approach.

The simplest "fix" to do would be to use a BufferedReader and a StringBuilder.

However the most efficient way to read data is to read bytes, into a ByteBuffer and parse the "lines". I assume you are receiving ASCII text. You could write the parser to be able to process the content and the end of line in one stage (ie with one pass of the data)

Using the last approach, here is an example (including code) of where I am parsing an XML message from a socket and replying in XML. The typical latency was 16 micro-seconds and the throughput was 264K per second.

http://vanillajava.blogspot.com/2011/07/send-xml-over-socket-fast.html


You can do something like the following which likely to be fast enough

BufferedReader br = new BufferedReader(_in);
for(String line; ((line = br.readline()) != null;) {
    if(line.indexOf('\0') >= 0)
       for(String part: line.split("\0"))
          parsePlayerPacket(part);
    else
       parsePlayerPacket(line);
}

If you find this solution dead simple and you are familiar with ByteBuffer you might consider using those.


I had the kind of a same problem at one of my applications I wrote. My Application took 50% cpu (in a dual core).

What I made then to resolve the Problem, is let the Thread sleeping 1 timetick

Thread.sleep(1);

I hope this is helpfull for you

edit:

oh and for what is that ?
}catch(IOException e)
{
kickPlayer();
}catch(Exception e)
{
kickPlayer();
}

I think you don't need the IOException Catch (the Exception catch, catches every kind of exception)


That exception handling just hurted my eyes. There's no point in calling kickPlayer() inside catch blocks since you are calling it again in finally. Finally executes (almost) always.

And now about your problem, forget my previous answer, I was a bit asleep XD. I don't see anything prone to loop forever in the posted while loop. InputStream.read() either returns -1 when there's no more data or throws an exception. The problem must be in other code, or maybe is a threading problem.

As they have told you in other answers, try to use buffered streams, reading a block of characters instead of only one at a time, and replace the string concatenation for StringBuilder's append method. This should improve performance, but not sure if it will solve the problem (maybe it appears in 24h instead of 12).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜