java套接字服务器程序在一段时间后不接受连接

时间:2016-06-03 06:59:35

标签: java multithreading sockets

我有一个套接字客户端应用程序,它侦听指定端口上主线程中的传入连接,接受传入连接并为每个连接启动用户线程。

此设置可以在某一天运行,然后应用程序停止接受任何新的新连接。恢复的唯一方法是重启应用程序。我不知道为什么会发生这种情况...... 这是我的主要内容,它为每个连接接受并启动一个新线程。

while(ServerOn)
   {
        ServerSocket myServerSocket;
        private static ArrayList<Socket> connecitons; 
    try {
        // Accept incoming connections.
        Socket conn = myServerSocket.accept();
        // adds the new connections to the socket
        connections.add(conn);

        // accept() will block until a client connects to the server.
        // If execution reaches this point, then it means that a client
        // socket has been accepted.

        // For each client, we will start a service thread to
        // service the client requests.

        // Start a Service thread

        ServerThread cliThread = new ServerThread(conn);
        cliThread.start();
        } catch (IOException ioe) {
            System.out.println("Exception encountered on accept. Ignoring. Stack Trace :");
            ioe.printStackTrace();
        }
    }
    try {
        myServerSocket.close();
        System.out.println("Server Stopped");
    } catch (Exception ioe) {
        System.out.println("Problem stopping server socket");
        System.exit(-1);
    }
    }

请帮忙。

编辑1

这是类声明:

class ServerThread extends Thread {
    Socket conn;
    boolean m_bRunThread = true;
    InputStream in = null;
    OutputStream outStream = null;



    //calling the 1-argument constructor with the socket parameters
    ServerThread(Socket s) {
        conn = s;
    }

    //Subclasses of Thread should override this method.
    public void run() {
    //lot of variables declared here.

    try {
            // Class InputStream is used for receiving data (as bytes) from client. 
            in = conn.getInputStream();
            // Class OutputStream is used for sending data (as bytes) to client.
            outStream = conn.getOutputStream();
            /*
             * 1. Go to Read Thread 
             * 2. Check for incoming data stream from Client 
             * 3. Go to read routine and process only if the data is received from the client 
             * 4. If there is no data for X minutes then close the socket.
             */
            conn.setSoTimeout(time in milliseconds);
            String inLine=null;

            while (m_bRunThread) {
                // read incoming stream
                while ((c=in.read(rec_data_in_byte))!= -1) 

                {...............

并且run方法继续......

3 个答案:

答案 0 :(得分:1)

我的观察是基于您提供的上述代码。我在下面看到一些对我来说毫无疑问的事情:

  1. private static ArrayList<Socket> connecitons;
  2. 我不需要这份清单。根据代码,我们总是在每个请求的列表中添加conn个对象。 我们没有在任何地方删除它们(我还没有看到完整的代码)。如果是这种情况,则此列表的大小总是在增长。它可能会导致OutOfMemoryError。

    1. while (m_bRunThread) {....}
    2. 在ServerThread类的run()方法中,变量m_bRunThread是否始终为true。如果是这种情况,则该线程永远不会被终止。所以没有。活线程的数量不断增加。它会使应用程序无响应。 对于ConcurrentModificationException:因为您没有使用Iterator(或for-each循环)来迭代列表,所以即使在多线程场景中也不会抛出此异常。

答案 1 :(得分:0)

应删除m_bRunThread上的外部循环。您只需要内部读取循环,它应该在终止或获得异常时关闭套接字。

答案 2 :(得分:0)

我观察到的另一件事。根据提供的代码,对于每个传入连接,您将创建一个新的服务线程。但我不认为每次创建一个新主题都是个好主意。

因为假设如果每秒有1000个连接,则意味着我们每秒创建新的1000个线程,因此这意味着管理1000个线程需要很大的开销。

由于线程的上下文切换的开销,应用程序可能变得无响应。 其次会有频繁的GC(垃圾收集器)循环,有时可能会导致STW(停止世界)的情况。

所以我的建议是:

你可以使用某种线程池,也可以是Executor框架,我们可以通过提供参数(例如核心池大小,最大池大小,保持空闲线程的活动时间等)来创建我们自己的public class InfixPostfixEvaluator { /** * Operators in reverse order of precedence. */ private static final String operators = "-+/*"; private static final String operands = "0123456789"; public int evalInfix(String infix) { return evaluatePostfix(convert2Postfix(infix)); } public String convert2Postfix(String infixExpr) { char[] chars = infixExpr.toCharArray(); Stack&lt;Character&gt; stack = new Stack&lt;Character&gt;(); StringBuilder out = new StringBuilder(infixExpr.length()); for (char c : chars) { if (isOperator(c)) { while (!stack.isEmpty() && stack.peek() != '(') { if (operatorGreaterOrEqual(stack.peek(), c)) { out.append(stack.pop()); } else { break; } } stack.push(c); } else if (c == '(') { stack.push(c); } else if (c == ')') { while (!stack.isEmpty() && stack.peek() != '(') { out.append(stack.pop()); } if (!stack.isEmpty()) { stack.pop(); } } else if (isOperand(c)) { out.append(c); } } while (!stack.empty()) { out.append(stack.pop()); } return out.toString(); } public int evaluatePostfix(String postfixExpr) { char[] chars = postfixExpr.toCharArray(); Stack&lt;Integer&gt; stack = new Stack&lt;Integer&gt;(); for (char c : chars) { if (isOperand(c)) { stack.push(c - '0'); // convert char to int val } else if (isOperator(c)) { int op1 = stack.pop(); int op2 = stack.pop(); int result; switch (c) { case '*': result = op1 * op2; stack.push(result); break; case '/': result = op2 / op1; stack.push(result); break; case '+': result = op1 + op2; stack.push(result); break; case '-': result = op2 - op1; stack.push(result); break; } } } return stack.pop(); } private int getPrecedence(char operator) { int ret = 0; if (operator == '-' || operator == '+') { ret = 1; } else if (operator == '*' || operator == '/') { ret = 2; } return ret; } private boolean operatorGreaterOrEqual(char op1, char op2) { return getPrecedence(op1) &gt;= getPrecedence(op2); } private boolean isOperator(char val) { return operators.indexOf(val) &gt;= 0; } private boolean isOperand(char val) { return operands.indexOf(val) &gt;= 0; } } )。所以现在你不必管理线程的创建和生命周期。 现在可以重用空闲线程。 由于频繁的GC的可能性会降低,因此您的应用程序将更具响应性。

即使你可以使用Executor的框架内置固定大小的线程池,实现,你也不需要管理其余的开销,除了你需要通过总数的一件事。 。参数中的线程数,您希望在那里为请求提供服务。

以下是示例代码:

ThreadPoolExecutor

以下是任务实施..

        private Executor executor = Executors.newFixedThreadPool(10);
        private ArrayList<Socket> connecitons = new ArrayList<>();
        while(ServerOn)
        {
            ServerSocket myServerSocket;

            try {
                // Accept incoming connections.
                Socket conn = myServerSocket.accept();
                connections.add(conn);

                executor.execute(new ServerThreadRunnable(conn));
            } catch (IOException ioe) {
                System.out.println("Exception encountered on accept. Ignoring. Stack Trace :");
                ioe.printStackTrace();
            }
        }
        try {
            myServerSocket.close();
            System.out.println("Server Stopped");
        } catch (Exception ioe) {
            System.out.println("Problem stopping server socket");
            System.exit(-1);
        }