Каков наилучший способ управления текстовыми клиент-серверными соединениями?

Я хочу написать небольшую клиент-серверную текстовую игру, которая обрабатывает множество клиентских подключений и постоянно влияет на игровое состояние. Мне интересно, как лучше всего обрабатывать несколько соединений, чтобы команды обрабатывались в порядке их поступления на сервер.

В идеале я не собираюсь использовать преимущества многопоточности, по крайней мере, на уровне обработки команд. Я был бы согласен с тем, чтобы у каждого клиента был отдельный поток (чтобы блокировать ввод-вывод в каждом потоке), если впоследствии я смог объединить обработку в одном потоке.

Поскольку единственное взаимодействие между клиентом и сервером будет текстовым, я не уверен, как лучше настроить соединение. Если бы я выбрал блокировку ввода-вывода, как бы я поставил в очередь обработку в одном потоке?

В качестве альтернативы, если я выбираю неблокирующий ввод-вывод и использую селектор для запроса, когда клиенты записывают на сервер, как я могу прочитать строку неизвестной / неограниченной длины без использования 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

Другие вопросы по тегам