我有一个简单的套接字服务器(用于HL7通信)。当它在生产中运行时间更长时,套接字线程会挂起并消耗大量的CPU时间。
这是侦听器线程的相关代码(缩写):
public void run() {
try {
serverSocket = new ServerSocket(port, backlog, bindAddress);
serverSocket.setSoTimeout(timeout); // 1000 ms
do {
Socket socket = null;
try {
socket = serverSocket.accept();
} catch (SocketTimeoutException to) {
socket = null;
} catch (InterruptedIOException io) {
socket = null;
} catch (IOException e) {
logger.fatal("IO exception while socket accept", e);
socket = null;
}
try {
if (socket != null)
processConnection(socket);
} catch (RuntimeException e) {
logger.fatal("caught RuntimeException trying to terminate listener thread", e);
}
} while (running);
} catch (IOException e) {
logger.fatal("error binding server socket - listener thread stopped", e);
}
}
此代码启动一个新线程来处理传入连接:
protected void processConnection(Socket socket) {
Hl7RequestHandler requestHandler = createRequestHandler();
requestHandler.setSocket(socket);
requestHandler.start();
}
这是请求处理程序线程的代码(keepAlive设置为true):
public void run() {
try {
setName("Hl7RequestHandler-" + socket.getPort());
processRequest();
} catch (IOException e) {
logger.fatal("IO exception during socket communication", e);
}
}
public void processRequest()
throws IOException {
socket.setSoTimeout(socketTimeout); // 1000 ms
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
BufferedReader inputReader = new BufferedReader(new InputStreamReader(inputStream, encoding));
Writer outputWriter = new OutputStreamWriter(outputStream, encoding);
int timeouts = 0;
boolean failure = false;
do {
StringBuilder message = new StringBuilder();
try {
char c;
do {
c = (char)inputReader.read();
if ((c == CARRIAGE_RETURN || c == START_OF_MESSAGE) &&
message.length() == 0)
else if (c != END_OF_MESSAGE && ((short)c) != -1)
// ein Byte "Nutzlast"
message.append(c);
} while (c != END_OF_MESSAGE && ((short)c) != -1);
} catch (SocketTimeoutException te) {
timeouts++;
if(!keepAlive && timeouts >= 3 ) {
socket.close();
return;
}
}
String messageStr = message.toString();
if (messageStr.length() == 0)
continue;
failure = !processMessage(messageStr, outputWriter);
outputWriter.flush();
outputStream.flush();
// nächste Runde?
if (!keepAlive || failure)
socket.close();
} while (keepAlive && !failure);
}
当我在本地测试时,效果很好。
但是在生产中,有多个请求处理程序线程“挂起”。 “Keep Alive”用于保持打开连接等待更多消息。 (为了避免一直打开新的连接。)我假设inputReader.read()在超时1s后返回-1,这导致再次调用该方法。为什么这会占用所有CPU时间?
你有什么建议吗?
提前致谢, 的Matthias
答案 0 :(得分:2)
我能直接看到的一件事是:
char c;
do {
c = (char)inputReader.read();
if ((c == CARRIAGE_RETURN || c == START_OF_MESSAGE) &&
message.length() == 0)
else if (c != END_OF_MESSAGE && ((short)c) != -1)
// ein Byte "Nutzlast"
message.append(c);
} while (c != END_OF_MESSAGE && ((short)c) != -1);
是inputReader.read()到char的强制转换。 BufferedReader.read()返回一个有符号值的int。您将其转换为无符号值的char,如果存在负号,则丢弃负号,即缩小转换。然后转换为short并不会带回负号(如果有的话)。 尝试重写为:
char c;
int val;
do {
val = inputReader.read();
// do this if you want, you don't have to
c = (char) val;
if ((c == CARRIAGE_RETURN || c == START_OF_MESSAGE) &&
message.length() == 0)
else if (c != END_OF_MESSAGE && ((short)c) != -1)
// ein Byte "Nutzlast"
message.append(c);
} while (c != END_OF_MESSAGE && val != -1);
我再看看你的循环,我很困惑。
char c;
do {
c = (char)inputReader.read();
if ((c == CARRIAGE_RETURN || c == START_OF_MESSAGE) &&
message.length() == 0)
else if (c != END_OF_MESSAGE && ((short)c) != -1)
// ein Byte "Nutzlast"
message.append(c);
} while (c != END_OF_MESSAGE && ((short)c) != -1);
你的if语句的逻辑令人困惑(至少对我来说)。 第一个if子句没有语句,甚至没有空语句。 你必须有{}或a;你的代码是否编译?