Каков наилучший способ управления текстовыми клиент-серверными соединениями?
Я хочу написать небольшую клиент-серверную текстовую игру, которая обрабатывает множество клиентских подключений и постоянно влияет на игровое состояние. Мне интересно, как лучше всего обрабатывать несколько соединений, чтобы команды обрабатывались в порядке их поступления на сервер.
В идеале я не собираюсь использовать преимущества многопоточности, по крайней мере, на уровне обработки команд. Я был бы согласен с тем, чтобы у каждого клиента был отдельный поток (чтобы блокировать ввод-вывод в каждом потоке), если впоследствии я смог объединить обработку в одном потоке.
Поскольку единственное взаимодействие между клиентом и сервером будет текстовым, я не уверен, как лучше настроить соединение. Если бы я выбрал блокировку ввода-вывода, как бы я поставил в очередь обработку в одном потоке?
В качестве альтернативы, если я выбираю неблокирующий ввод-вывод и использую селектор для запроса, когда клиенты записывают на сервер, как я могу прочитать строку неизвестной / неограниченной длины без использования ByteBuffer заданного размера? Неблокирование также способствует сохранению обработки в одном потоке, поскольку она может просто считывать данные с клиентских подключений по мере того, как они отправляют новые данные. Однако, когда я попытался реализовать это с помощью read/writeUTF, я столкнулся с IllegalBlockingModeException heh.
Любые ответы на вопросы или предложения о том, как сделать это способом, который я не упомянул, будут искренне оценены! Я довольно плохо знаком с клиентами и серверами, поэтому я не знаю, будут ли java.io или java.nio наиболее подходящими.
Извините за запутанный вопрос. Я думаю, что сбежал с собой.
2 ответа
Мнения расходятся, но я бы определенно выбрал один поток для каждого клиента. Связь с одним потоком обработки может затем проходить через LinkedBlockingQueue или просто синхронизированный LinkedList.
Примерно так в потоке для каждого клиента:
public class Client implements Runnable, ResponseOutput {
private final BufferedReader br;
private final PrintWriter pw;
public Client(Socket s) {
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
pw = new PrintWriter(s.getOutputStream());
}
// defined by the ResponseOutput interface
public void sendReply(String reply) {
pw.println(reply);
}
public void run() {
try {
while (true) {
String s = br.readLine();
if (s==null)
break;
Processor.queue(new Processor.InputItem(this, s));
}
} catch (IOException ioe) {
... error handling ...
}
}
}
Тогда это для обработки:
public class Processor implements Runnable {
static public class InputItem {
final ResponseOutput client;
final String command;
public InputItem(ResponseOutput client, String command) {
this.client = client;
this.command = command;
}
}
static private Processor instance;
static public void queue(InputItem item) {
instance.commandQueue.add(item);
}
private BlockingQueue<InputItem> commandQueue;
public void run() {
try {
while (true) {
InputItem item = commandQueue.take();
String reply = doStuff(item.command);
item.client.sendReply(reply);
}
} catch (InterruptedException ie) {
... error handling ....
}
}
}
В пределах InputItem
Класс, вы также можете включить ссылку на любое состояние игры, которая нуждается в обновлении. Поскольку его изменяет только поток обработки, вы можете сделать это без какой-либо синхронизации.
Я не эксперт в клиентских системах, но я поделюсь парой советов
В зависимости от ваших потребностей вы можете просто настроить сервер Tomcat и выполнить http-запрос, это довольно просто и, конечно, все на Java.
недостатком является то, что запрос может быть немного медленным.
Второй вариант, который вы можете проверить, это RMI.
Концепция проста: вы подключаетесь к другому компьютеру, и когда это делается, вы вызываете методы на другом компьютере из локального объекта в вашем коде.
http://java.sun.com/developer/onlineTraining/rmi/RMI.html
это может показаться немного сложным (а иногда отладка стека на нескольких компьютерах немного сложнее), но я рекомендую, потому что это сохраняет ваш код чистым.
Наконец, вы можете попробовать розетки, но там по своему усмотрению:P