Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/373.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Executors.newFixedThreadPool的异步Java NIO需要帮助_Java_Sockets_Buffer_Threadpool - Fatal编程技术网

使用Executors.newFixedThreadPool的异步Java NIO需要帮助

使用Executors.newFixedThreadPool的异步Java NIO需要帮助,java,sockets,buffer,threadpool,Java,Sockets,Buffer,Threadpool,嘿,伙计们,我正在开发一个服务器程序,它可以很好地扩展并服务于潜在的数千个客户端。问题是,我觉得ApacheMina太重了,所以我决定不使用它,而是编写了自己的客户机侦听器。我从来没有真正用Java执行过异步套接字操作(C#使这变得容易多了,但我真的更喜欢用Java编写这个项目,因为除了套接字读取之外,我对它在所有方面都比较熟悉),所以试图理解如何正确使用线程池对我来说很困难。我使用ApacheMina文档了解应该如何做。我有两个问题: 线程池使用是否正确?ApacheMina的默认线程大小是C

嘿,伙计们,我正在开发一个服务器程序,它可以很好地扩展并服务于潜在的数千个客户端。问题是,我觉得ApacheMina太重了,所以我决定不使用它,而是编写了自己的客户机侦听器。我从来没有真正用Java执行过异步套接字操作(C#使这变得容易多了,但我真的更喜欢用Java编写这个项目,因为除了套接字读取之外,我对它在所有方面都比较熟悉),所以试图理解如何正确使用线程池对我来说很困难。我使用ApacheMina文档了解应该如何做。我有两个问题:

  • 线程池使用是否正确?ApacheMina的默认线程大小是CPU内核数+1,但我真的应该为Core2Duo使用3线程线程池来接受数千个客户端吗
  • 我知道为从客户机接收到的每条消息重新分配两次缓冲区(每条消息是两个数据包,一个报头是常数4字节,另一个内容数据包的长度在报头中指定)。有没有一种简单的方法可以使用固定大小的缓冲区来检查缓冲区溢出,从而使行为保持不变,但不必不断地重新分配缓冲区
  • 以下是我如何启动侦听器:

    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) {
            }
        }
    }
    
    客户端会话相关代码:

    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类的代码,但我很确定这些方法/类的目的是显而易见的。

    阻塞IO场景中的线程数必须根据客户端数和每个客户端连接打开的时间来计算。 每个用户的每个连接都需要一个线程


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

    没关系,伙计们。我意识到ApacheMina实际上使用NIO,这就是为什么我感到困惑的原因。使用选择器处理请求实际上只需要一个线程。谢谢你的回答,很抱歉给你带来困惑

    突出的是,你只是在吞咽例外。至少把它们记录下来。这些只是代码片段。在我的实际代码中,我使用java.util.Logger和详细的消息来记录它们?我不使用Java的非阻塞I/O类,因为我宁愿使用线程而不是选择器。线程要简单得多。所以我只使用Java的常规同步ServerSocket。将我从异步线程池方法转移到非阻塞选择器方法,这看起来不太令人信服。另外,我希望它能够很好地扩展到多核服务器。这正是我在看到这个关于ApacheMina的网站之前所想的:在标题为“配置I/O工作线程的数量”的部分下,除了I/O处理器线程外,每个工作线程一次只运行一个线程。然而,I/O处理器线程的最大数量是CPU核心数+1,这让我感到困惑。也许它们的工作原理与我所采用的方法不同?这个答案应该是一个评论。