我有这个Java游戏服务器,可处理多达3,000个tcp连接,每个播放器或每个tcp连接都有自己的线程,每个线程都是这样的:
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);
}
}
代码运行正常,我知道每个玩家的每个线程都是个坏主意,但我现在也会这样做。服务器在快速机器上运行良好(6cor x2,64bits,24GB RAM,Windows Server 2003)。
但是在某些时候,在UpTime大约12个小时之后,服务器开始在某个地方循环...我知道因为java进程无限地占用了99%的CPU,直到下次重启。 而且我很难分析应用程序,因为我不想打扰玩家。我使用的探查器(visualvm)总是最终破坏服务器而不告诉我问题出在哪里。
无论如何,在上面的那段代码中我想可能问题来自于:
while(_in.read(charCur, 0, 1)!=-1)
(_in
是客户端套接字的BufferedReader
。
_in.read()
是否有可能无限地返回其他内容以保持我的代码运行并占用99%的资源?我的代码有问题吗?我不明白一切,我只写了一半。
答案 0 :(得分:2)
一次读取一个char几乎与使用+ =构建String一样慢。我无法告诉你哪个更糟糕。如果单个连接使用这种方法绑定整个核心,我不会感到惊讶。
最简单的“修复”是使用BufferedReader和StringBuilder。
然而,读取数据的最有效方法是将字节读入ByteBuffer并解析“行”。我假设您正在接收ASCII文本。您可以编写解析器,以便能够在一个阶段处理内容和行尾(即一次传递数据)
使用最后一种方法,这里是我从套接字解析XML消息并以XML回复的示例(包括代码)。典型的延迟为16微秒,吞吐量为每秒264K。
http://vanillajava.blogspot.com/2011/07/send-xml-over-socket-fast.html
您可以执行以下可能足够快的操作
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);
}
如果你发现这个解决方案很简单并且熟悉ByteBuffer,你可以考虑使用它们。
答案 1 :(得分:0)
我在我写的一个应用程序中遇到了同样的问题。我的应用程序占用了50%的CPU(双核)。
我所做的是解决问题,让线程睡1时间点
Thread.sleep(1);
我希望这对你有所帮助
编辑:
哦,那是什么?}catch(IOException e)
{
kickPlayer();
}catch(Exception e)
{
kickPlayer();
}
我认为你不需要IOException Catch(异常捕获,捕获各种异常)
答案 2 :(得分:0)
那个异常处理只是伤害了我的眼睛。因为你最后再次调用它,所以在catch块中调用kickPlayer()是没有意义的。最后执行(几乎)总是。
现在关于你的问题,忘了我之前的回答,我有点睡着了XD。在发布的while循环中,我没有看到任何容易循环的东西。当没有更多数据或抛出异常时,InputStream.read()返回-1。问题必须在其他代码中,或者可能是线程问题。
正如他们在其他答案中告诉你的那样,尝试使用缓冲流,一次只读一个字符块而不是一个,并替换StringBuilder的append方法的字符串连接。这应该可以提高性能,但不确定它是否能解决问题(可能会在24小时而不是12小时内出现)。