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