【问题标题】:java socket server program not accepting connections after some timejava socket服务器程序在一段时间后不接受连接
【发布时间】:2016-06-03 06:59:35
【问题描述】:

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

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

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方法继续……

【问题讨论】:

  • 编辑了代码。它的 while 循环设置为 true。
  • 您确定您的应用程序的输出到 stdout/stderr 对您是可见的吗?你看,仅仅在某处打印异常并不是一种非常可靠的处理方式。
  • @Jägermeister- 是的,我知道,但这是主线程,如果它退出,整个应用程序应该停止,这不会发生。创建的客户端线程继续无缝工作,只是不再接受新的传入连接。
  • @Jayesh Tripathi。即使主线程停止,如果有其他线程(不是守护进程)正在运行,应用程序也不会停止。顺便说一句,最后一行中的 System.exit 并不总是被调用。
  • 除非客户端线程将自己从数组中删除,否则即使拥有它也没有多大意义,如果你拥有它,你必须同步所有对它的访问。例如,您可能会收到 ConcurrentModificationException,这是一个运行时异常。当您的应用程序停止接受时,(a) 它是否仍在运行,并且 (b) netstat -nap tcp 是否仍将端口显示为 LISTENING?我也想知道ServerThread 的构造函数到底做了什么。如果它做任何 I/O,甚至构造对象流,它也不应该。

标签: java multithreading sockets


【解决方案1】:

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

  1. private static ArrayList&lt;Socket&gt; connecitons;

我不需要这个列表。根据代码,我们总是为每个请求在此列表中添加 conn 对象。 我们不会在任何地方删除它们(我还没有看到完整的代码)。如果是这种情况,那么这个列表的大小总是在增长。并且可能会导致 OutOfMemoryError。

  1. while (m_bRunThread) {....}

在ServerThread类的run()方法中,变量m_bRunThread是否始终为真。如果是这种情况,那么这个线程将永远不会被终止。所以没有。活动线程的数量不断增加。它会使应用程序无响应。 对于ConcurrentModificationException:由于您没有使用Iterator(或for-each 循环)对列表进行迭代,因此即使在多线程情况下也不会抛出此异常。

【讨论】:

  • 1.是的,它可能会出现OutOfMemoryError,但这应该会停止整个应用程序。在这种情况下,应用程序正在运行,产生的线程正在运行它,只是应用程序在一段时间后拒绝任何新连接。注意:已检查防火墙 2。while (m_bRunThread) {....} 循环在每个异常处理和终止点都设为假。 仔细检查
【解决方案2】:

m_bRunThread 的外层循环应该被移除。您只需要内部读取循环,它应该在终止或遇到异常时关闭套接字。

【讨论】:

  • 添加了m_bRunThread 循环作为主线程的故障保护,而循环while(ServerOn) 在运行方法结束时我检查if(!ServerOn){m_bRunThread=false; conn.close;}但我仍然要问这是否能解决问题。 netstat -nap tcp 正在等待结果,因为它从昨天开始还没有停止。
  • 把它放在那里没有任何意义,所以你应该删除它。正如你现在所拥有的,这些线程会在客户端断开连接后永远无意识地旋转,这是对 CPU 的浪费,并且永远不会退出,这是资源泄漏。
  • @EJP- 应用程序今天停止接受连接,netstat -nap tcp 将端口显示为 LISTENING
【解决方案3】:

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

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

由于线程上下文切换的开销,应用程序可能会变得无响应。 其次,会有频繁的 GC(garbage collector) 循环,有时又会导致 STW(stop the world) 的情况。

所以我的建议是:

您可以使用某种线程池,可能是 Executor 框架,我们可以通过提供参数(例如核心池大小、最大池大小、空闲线程的保持活动时间等)来创建自己的ThreadPoolExecutor。所以现在您不必管理线程的创建和生命周期。 现在可以重用空闲线程。 由于频繁 GC 的机会将减少,您的应用程序将更加敏感。

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

下面是示例代码:

        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);
        }

下面是任务实现..

class ServerThreadRunnable implements Runnable {
    private Socket conn;
    ServerThread(Socket s) {
        conn = s;
    }
    public void run() {
        //Here the implementation goes as per your requirement
    }
}

【讨论】:

  • 他每个连接都有一个线程,而不是每个请求,这是一个正常的模式。不要对非代码文本使用代码格式。
  • @EJP,,实际上我是新来的,但我明白你的意思,我会注意的,根据我的想法,对于每个 conn,我们总是在创建一个新线程,所以我不确定是否是个好主意。这就是为什么我建议不要总是使用线程池来创建新线程。
  • 但是你实际上说的是每个请求一个新线程,这是不正确的。如果这不能反映你的意思,你应该编辑你的答案。
  • @EJP,感谢您指出,我已经编辑了答案以使其更加清晰。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-09
相关资源
最近更新 更多