java - 套接字通信: Thread hangs

标签 java multithreading sockets communication

我有一个简单的套接字服务器(用于 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);
}

当我在本地测试时,效果很好。

但在生产中,有多个请求处理程序线程“挂起”。 “保持 Activity ”是为了保持连接打开等待更多消息。 (为了避免一直打开新连接。)我假设 inputReader.read() 在 1 秒超时后返回 -1,这会导致再次调用该方法。为什么这会耗尽所有 CPU 时间?

你有什么建议吗?

提前致谢, 马蒂亚斯

最佳答案

我可以立即看到的一件事是:

         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,如果存在负号,则丢弃负号,这是一种缩小转换。然后转换为空头不会带回负号(如果有的话)。 尝试重写为:

         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 子句没有任何语句,甚至没有空语句。 您必须有 {} 或 ;你的代码能编译吗?

关于java - 套接字通信: Thread hangs,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9001981/

相关文章:

5 分钟后 iOS voip 应用程序在后台模式下没有响应

networking - 如何识别客户端(客户端套接字)?

java - 绘制圆圈并将其设置为在 Canvas 上可见

java - 使用 Java 在 XMPP 服务器中创建新用户

java - 用于生成名称的多线程

c++ - Clang ThreadSanitizer : unlock of an unlocked mutex,和一个原子正在创建数据争用

java - 四分区矩阵搜索

java - XML 不会加载 TestNG Java 类

c - 多线程会做write()交错吗

multithreading - 使用阻塞调用时如何退出程序