使用Executors.newFixedThreadPool进行异步Java NIO所需的帮助

时间:2011-01-16 15:25:51

标签: java sockets buffer threadpool

嘿伙计们,我正在开发一个服务器程序,该程序可以很好地扩展并为数千个客户提供服务。问题是,我觉得Apache MINA太重了,所以我决定不使用它而是写了我自己的客户端监听器。我从来没有真正用Java执行异步套接字操作(C#使得这么简单,但我真的更喜欢用Java编写这个项目,因为除了套接字读取之外,我对它更熟悉),所以试着理解如何使用它正确的线程池对我来说很难。我使用Apache MINA文档来了解应该如何完成任务。我有两个问题:

  1. 线程池是否正确使用? Apache MINA的默认线程大小是CPU核心数+ 1,但是我真的应该为我的Core 2 Duo使用3线程线程池来接受数千个客户端吗?
  2. 我知道为从客户端收到的每条消息重新分配缓冲区两次(每条消息是两个数据包,一个标头是一个常量4字节,一个内容数据包的长度在标头中指定)。是否有一种简单的方法可以使用固定大小的缓冲区来检查缓冲区溢出,以便行为仍然相同,但缓冲区不必经常重新分配?
  3. 以下是我启动听众的方式:

    ClientListener cl = new ClientListener(1234);
    cl.init();
    new Thread(cl).start();
    

    以下是ClientListener的相关代码:

    private static final int THREADS = Runtime.getRuntime().availableProcessors() + 1;
    private ServerSocket socket;
    private ExecutorService threadPool;
    private int port;
    
    public ClientListener(int port) {
        this.port = port;
        threadPool = Executors.newFixedThreadPool(THREADS);
    }
    
    public void init() {
        try {
            socket = new ServerSocket(port);
        } catch (IOException ex) {
        }
    }
    
    public void run() {
        while (true) {
            try {
                ClientSession s = new ClientSession(socket.accept());
                threadPool.execute(s);
            } catch (IOException ex) {
            }
        }
    }
    

    ClientSession相关代码:

    private Socket socket;
    private byte[] buffer;
    private boolean isHeader;
    
    public ClientSession(Socket socket) {
        this.socket = socket;
        this.buffer = new byte[4];
        this.isHeader = true;
    }
    
    public void run() {
        InputStream in;
        try {
            in = socket.getInputStream();
            out = socket.getOutputStream();
        } catch (IOException ex) {
            return;
        }
        while (!socket.isClosed()) {
            try {
                int read = in.read(buffer);
                if (read == -1)
                    break;
                receive(read);
            } catch (IOException ex) {
                break;
            }
        }
    }
    
    private void receive(int readBytes) {
        if (isHeader) {
            if (readBytes >= 4) {
                buffer = new byte[getPacketLength(buffer)];
                isHeader = false;
            } else {
                System.out.println("Not enough data received from client " + socket.getInetAddress() + " to decode packet.");
            }
        } else {
            if (readBytes >= buffer.length) {
                processMessage(new LittleEndianByteArrayReader(decryptData(buffer)), this);
                buffer = new byte[4];
                isHeader = true;
            } else {
                System.out.println("Not enough data received from client " + socket.getInetAddress() + " to decode packet (needed " + buffer.length + ", received " + readBytes + ").");
            }
        }
    }
    

    您不需要知道getPacketLength,processMessage,decryptData和LittleEndianByteArrayReader类的代码,但我很确定这些方法/类的用途是显而易见的。

2 个答案:

答案 0 :(得分:0)

阻止IO方案中的线程数必须通过客户端数量和每个客户端连接打开的时间来计算。 每个用户的每个连接都需要在线程上。

只有三个线程,用户只需打开三个TCP连接并且不向服务器发送任何数据,就可以直接阻止服务器直到连接超时。

答案 1 :(得分:0)

没关系。我意识到Apache MINA实际上使用的是NIO,这就是为什么我感到困惑。它确实只需要一个线程来使用选择器来处理请求。感谢您的所有答案,对此感到抱歉!