【发布时间】:2011-11-09 00:44:31
【问题描述】:
我有一个 JAVA 游戏服务器,每个 TCP 连接使用 1 个线程。 (我知道这很糟糕,但我现在必须保持这种状态)。在(3.2Ghz 6cor x2 机器,24GB RAM,windows server 2003 64bits)上,这是一段代码:
public void run()
{
try
{
String packet = "";
char charCur[] = new char[1];
while(_in.read(charCur, 0, 1)!=-1 && Server.isRunning)
{
if (charCur[0] != '\u0000' && charCur[0] != '\n' && charCur[0] != '\r')
{
packet += charCur[0];
}else if(!packet.isEmpty())
{
parsePlayerPacket(packet);
packet = "";
}
}
}catch(Exception e)
{
e.printStackTrace();
}
finally
{
try{
kickPlayer();
}catch(Exception e){e.printStackTrace();};
Server.removeIp(_ip);
}
}
大约 12 小时或更长时间的服务器正常运行(以及大约 3.000 名玩家连接)后,服务器开始永远占用所有 12 个 CPU 的 100%,直到我手动重新启动 JAVA 应用程序。所以游戏开始非常糟糕,我的玩家开始抱怨。
我已经尝试分析应用程序,这是我想出的:
所以我猜测问题来自这里:
while(_in.read(charCur, 0, 1)!=-1 && Server.isRunning)
知道变量“_in”是套接字输入的读取器:(_in = new BufferedReader(new InputStreamReader(_socket.getInputStream())))。
到底为什么 _in.read() 在服务器运行时间很长之后会占用这么多 CPU?
我试过放一个 Thread.sleep(1);还有更多在 While 循环中,但不执行任何操作,我猜问题出在 BufferedReader.read() 方法内部。
有没有人知道是什么原因造成的?以及如何解决?
【问题讨论】:
-
令我感到惊讶的是,事实并非如此,而是您在循环中使用字符串连接。 为什么你一次只能读一个字符?
-
数据包是非常小的字符串,例如:“AB123”。所以没关系。
-
直到有人向您发起 DDOS 攻击,您最终会收到一个巨大的字符串。读取多个字符和 也 使用 StringBuilder 非常容易......为什么不这样做呢?
-
每个连接一个线程是一种非常糟糕的做法。每个核心一个线程是最佳的。也许最多 40-50,但 3k 简直是疯了。
-
我遇到过很多 DoS 攻击,我这里展示的代码只是一个干净的版本。我在该循环中实施了“最多 32 个字符的规则”。但是我仍然不知道如何修复这个字符串连接,我需要一些代码来知道你在说什么
标签: java multithreading sockets tcp profiling