【问题标题】:Java multithreaded server - each connection returns data. Processing on main thread?Java 多线程服务器 - 每个连接都返回数据。在主线程上处理?
【发布时间】:2010-12-22 07:00:06
【问题描述】:

我正在编写一个带有集成服务器的客户端,它应该无限期地等待新连接 - 并在一个线程上处理每个连接。

我想在系统范围内可用的消息处理程序在主线程中处理接收到的字节数组。但是,目前处理显然是在客户端线程上完成的。

我查看了 Futures,ExecutorService 的 submit(),但是当我在服务器中创建客户端连接时,数据将返回到服务器线程。如何从那里将它返回到主线程(可能在同步的数据包存储中?)以在不阻塞服务器的情况下处理它?

我当前的实现如下所示:

    public class Server extends Thread {
    private int port;
    private ExecutorService threadPool;

    public Server(int port) {
        this.port = port;
        // 50 simultaneous connections
        threadPool = Executors.newFixedThreadPool(50);
    }

    public void run() {
        try{
            ServerSocket listener = new ServerSocket(this.port);
            System.out.println("Listening on Port " + this.port);
            Socket connection;

            while(true){
                try {
                    connection = listener.accept();
                    System.out.println("Accepted client " + connection.getInetAddress());
                    connection.setSoTimeout(4000);

                    ClientHandler conn_c= new ClientHandler(connection);
                    threadPool.execute(conn_c);
                } catch (IOException e) {
                    System.out.println("IOException on connection: " + e);
                }
            }
        } catch (IOException e) {
            System.out.println("IOException on socket listen: " + e);
            e.printStackTrace();
            threadPool.shutdown();
        }
    }
}
class ClientHandler implements Runnable {
    private Socket connection;

    ClientHandler(Socket connection) {
        this.connection=connection;
    }

    @Override
    public void run() {
        try {
            // Read data from the InputStream, buffered
            int count;
            byte[] buffer = new byte[8192];

            InputStream is = connection.getInputStream();
            ByteArrayOutputStream out = new ByteArrayOutputStream();

            // While there is data in the stream, read it
            while ((count = is.read(buffer)) > 0) {
                out.write(buffer, 0, count);
            }
            is.close();
            out.close();

            System.out.println("Disconnect client " + connection.getInetAddress());
            connection.close();
            // handle the received data
            MessageHandler.handle(out.toByteArray());
        } catch (IOException e) {
            System.out.println("IOException on socket read: " + e);
            e.printStackTrace();
        }
        return;

    }
}

更新: 稳健的方法似乎是 TomTom 建议的 - 改用较新的 java.nio。由于这个项目的用途有限而且更多的是一个实验,我想知道在 java.io/java.net 中使用它的最佳方法:)

【问题讨论】:

  • 那么你为什么要在主线程上处理这些? NIO 确实允许您进行非阻塞处理(Netty 等库使其更易于使用),但是否有特定理由避免使用多线程方法?
  • 这些传入消息中的每一个都可能产生新的传出连接,因此,此服务器上的新传入连接,我想避免在新线程中捕获消息后运行所有内容

标签: java multithreading executorservice serversocket


【解决方案1】:

在我的选项中,您可以使用同步对象与主线程聊天,在将客户端连接添加到池后,主线程可以在接受和同步对象处阻塞,客户端处理后,将处理连接套接字和对队列的响应,然后唤醒同步对象,这样主线程就可以从队列中获取一些东西并处理它,主线程处理后,在接受处阻塞并在同步对象处等待。

基本上,您的架构是一种简单/直接的方式,新方式是使用 java nio,以获得更多并发服务器并获得更好的性能,而且 nio 也不是最好的方式......

【讨论】:

  • 对主线程中的传入数据包使用同步队列也是我想到的一个想法,但我不确定将客户端线程中接收到的数据返回到主线程。我会仔细研究一下,谢谢! :) (而且,目前,由于这是一个使用非常有限的项目,我想坚持使用 java.io,因为到目前为止我还没有使用过 nio。
【解决方案2】:

那我不会缩放。你这样做有什么理由吗?再加上你浪费了大量的内存——你不需要一个线程每个套接字。使用更好的 Java IO 库。就像作为 Java 的一部分使用了 10 年左右的那个(NGIO?)。它用一个套接字处理 x 个线程,只返回数据。

【讨论】:

  • 你的意思不是一个带有 X 套接字的线程吗?每个套接字一个线程不会扩展到超过 10,000 个连接,但这通常就足够了。我会更关心大小为 50 的固定大小的线程池!缓存线程池可能更合适。 ;)
  • 每个套接字一个线程是几个多线程服务器示例中推荐的。我将在没有线程的情况下尝试它,但这让我的问题保持开放,即如何在不阻塞服务器线程的情况下连续返回数据。 (固定大小的线程池是我解决这个问题的愚蠢尝试。我将切换到缓存线程池)
  • 嗯,你会发现很多过时的例子。检查en.wikipedia.org/wiki/New_I/O - 关于选择器的部分。基本上你有一个套接字列表,然后选择那些等待数据的,然后继续处理那些。不需要有一个线程等待每个套接字的数据。一个线程可以处理 1000 或 2000 个套接字,在循环中选择带有数据的套接字。这似乎是在 jdk 5 时间范围内添加的。您的示例代码可能是 ANCIENT。
  • 旧款式往往会再次流行起来。 ;) NIO 非阻塞套接字在 Java 1.4 中发布时是最好的。我并不是唯一一个发现在 Java 6 中使用带有阻塞线程的 NIO 可能是管理连接的最快、最有效的方法。恕我直言,使用调度程序模型会增加很多复杂性,而在现代系统中几乎没有价值。
  • 嗯,你还会发现很多“流行”的东西都是从不知道自己说什么的人那里流行起来的。例如,大多数人甚至不知道为什么关系数据库可以正常工作(关系理论)。 NIO + 每个 X 套接字(1000、2000 等)一个阻塞线程很好。但是,这不是“每个套接字一个线程”,问题还在于收益是否有真正的好处。他们不适合我 - 我有一个应用程序可以实时分发财务数据以处理服务。
猜你喜欢
  • 2015-03-24
  • 2018-04-28
  • 1970-01-01
  • 1970-01-01
  • 2017-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-21
相关资源
最近更新 更多