我正在开发一个项目,我必须托管一个服务器来获取输入流,解析数据并将其发送到数据库。连接到我的服务器的每个客户端都会发送一个输入流,一旦连接就永不停止。每个客户端都分配了一个套接字和它自己的解析器线程对象,因此服务器可以处理来自客户端的数据流。解析器对象只处理传入的数据并将其发送到数据库。
服务器/解析器生成器:
public void generateParsers() {
while (keepRunning) {
try {
Socket socket = s.accept();
// new connection
t = new Thread(new Parser(socket));
t.start();
} catch (IOException e) {
appLog.severe(e.getMessage());
}
}
}
解析器线程:
@Override
public void run() {
while (!socket.isClosed() && socket.isConnected()) {
try {
BufferedReader bufReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = bufReader.readLine();
String data = "";
if (line == null) {
socket.close();
} else if (Objects.equals(line, "<DATA")) {
while (!Objects.equals(line, "</DATA>")) {
data += line;
line = bufReader.readLine();
}
/*
Send the string that was build
from the client's datastream to the database
using the parse() function.
*/
parse(data);
}
}
} catch (IOException e) {
System.out.println("ERROR : " + e);
}
}
}
我的设置功能正常,但问题是当连接的客户端太多时,它会给我的服务器带来太大的压力,因此有太多的线程同时解析数据。解析传入数据和将数据发送到数据库几乎不会影响性能。瓶颈主要是从连接的客户端同时读取客户端的数据流。
有什么办法可以优化我目前的设置吗?我考虑限制连接数量,一旦收到完整的数据文件,解析它并移动到连接队列中的下一个客户端或类似的东西。
答案 0 :(得分:3)
瓶颈主要是并发阅读
没有。瓶颈是字符串连接。使用StringBuffer
或StringBuilder
。
当客户端断开连接时,可能是不正确的行为。很难相信这一点有用。它不应该:
BufferedReader
,否则你可能会丢失数据。 Socket.isClosed()
和Socket.isConnected()
没有做您认为他们做的事情:正确的循环终止条件是readLine()
返回null,或者抛出IOException
:
while ((line = bufReader.readLine()) != null)
如果客户端从不断开连接,那么限制并发连接数就不可能实现。你所要做的就是永远不会听第一个 N 之外的客户来连接,这可能不是你想要的。 “转移到下一个客户”永远不会发生。
答案 1 :(得分:2)
如果您的问题确实是在客户端连接时您所做的事情很昂贵,那么您将不得不使用客户端队列。最简单的方法是使用ExecutorService
和N个最大线程数。
例如
private ExecutorService pool=Executors.newFixedThreapPool(N);
... 然后
Socket socket = s.accept();
pool.submit(new Parser(socket)));
这会将Concurent客户端处理限制为N,并排队超过N的任何其他客户端。
还取决于您对数据的处理方式,您始终可以将流程拆分为阶段,例如
如果你有一些阻塞操作,如网络I / O或昂贵的等操作,这将特别有用。
在您的情况下,客户端不必等待整个后端程序完成。他只需要提供数据,因此将数据读取和解析/持久分成单独的阶段(子任务)听起来像是合理的方法。