シンプルなソケットサーバー(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()が-1のタイムアウトの後に-1を返すと仮定します。その結果、メソッドが再び呼び出されます。なぜこれですべてのCPU時間が消費されますか?
アドバイスをいただけましたか?事前に
おかげで、 マティアス私はストレートオフに見ることができます
お返事ありがとうございます。私は確かにそれを変更します。しかしそれは時間消費を説明するのだろうか? –
あなたが提案したコードを変更しました。状況は同じです。 - inputReader.read()は-1を返し、直ちにもう一度呼び出されます。私は2つのリクエストハンドラスレッドで終わります。最初の人は喜んで(単一の)ピアと連携し、メッセージを受信して処理します。 2つ目は100%のCPUとループを無限に食べる(cpu load 1.0)。しばらくすると(おそらくピアが終了する)3番目のスレッドが表示され、さらにCPU負荷が増加します。 –
多分socket.setKeepAlive(true)を試してみます –