Нужна помощь с асинхронным Java NIO с использованием Executors.newFixedThreadPool - PullRequest
1 голос
/ 16 января 2011

Привет, ребята, я работаю над серверной программой, которая должна хорошо масштабироваться и обслуживать потенциально тысячи клиентов. Дело в том, что я чувствую, что Apache MINA слишком тяжелый, поэтому я решил не использовать его и вместо этого написал собственный клиентский слушатель. Я никогда не выполнял асинхронные операции с сокетами в Java (C # сделал это намного проще, но я действительно предпочел написать этот проект на Java, так как я более знаком с ним во всем, кроме чтения сокетов), поэтому пытался понять, как использовать Пул потоков правильно мне тяжело. Я использовал документацию Apache MINA, чтобы понять, как это сделать. У меня два вопроса:

  1. Правильно ли используется пул потоков? Размер потока по умолчанию в Apache MINA равен числу ядер процессора + 1, но стоит ли мне действительно использовать пул потоков из 3 потоков для моего Core 2 Duo, чтобы принимать тысячи клиентов?
  2. Я знаю, что перераспределение буфера дважды для каждого сообщения, полученного от клиента (каждое сообщение - это два пакета, один заголовок, который является константой 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) {
        }
    }
}

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 голосов
/ 20 января 2011

Неважно, ребята.Я понял, что Apache MINA на самом деле использует NIO, поэтому я запутался.Для обработки запросов с использованием селекторов действительно нужен только один поток.Спасибо за все ваши ответы и извините за путаницу!

0 голосов
/ 16 января 2011

Количество потоков в сценарии блокирования ввода-вывода должно рассчитываться по количеству клиентов и времени, когда будет открыто каждое клиентское соединение.Каждое соединение каждого пользователя требует в потоке.

Используя только три потока, пользователь может просто заблокировать ваш сервер до истечения времени ожидания соединения, просто открыв три TCP-соединения и не отправляя никаких данных на ваш сервер.

...