¿Cuál es la mejor manera de administrar las conexiones cliente-servidor basadas en texto?

Estoy buscando escribir un pequeño juego de texto basado en cliente-servidor que maneje múltiples conexiones de cliente y afecte de manera persistente el estado del juego. Me pregunto cuál sería la mejor manera de manejar múltiples conexiones de manera que los comandos se procesen en el orden en que llegan al servidor.

Idealmente, no estoy buscando aprovechar los subprocesos múltiples, al menos en el nivel de procesamiento de comandos. Estaría de acuerdo con que cada cliente tenga un hilo separado (para tener IO de bloqueo en cada hilo), siempre que pueda unificar el procesamiento en un solo hilo a partir de entonces.

Dado que la única comunicación entre el cliente y el servidor será texto, no estoy seguro de cuál es la mejor manera de configurar la comunicación. Si elijo bloquear el bloqueo de E / S, ¿cómo podría poner en cola el procesamiento para que ocurra en un solo hilo?

Alternativamente, si elijo IO sin bloqueo y uso un selector para consultar cuándo los clientes han escrito en el servidor, ¿cómo puedo leer una Cadena de longitud desconocida / ilimitada sin usar un ByteBuffer de tamaño establecido? El no bloqueo también favorece mantener el procesamiento en un solo hilo, ya que solo puede leer desde las conexiones del cliente cuando envían nuevos datos. Sin embargo, cuando intenté implementarlo con read / writeUTF me encontré con el IllegalBlockingModeException heh.

¡Cualquier respuesta a las preguntas o sugerencias sobre cómo hacer esto de una manera que no he mencionado sería sinceramente apreciada! Soy bastante nuevo en clientes y servidores, así que no sé si java.io o java.nio serían los más apropiados.

Perdón por la complicada pregunta. Creo que me escapé conmigo mismo.

Respuesta 1

Las opiniones difieren, pero definitivamente elegiría un solo hilo por cliente. La comunicación al subproceso de procesamiento único podría pasar por un LinkedBlockingQueue, o simplemente por un LinkedList sincronizado.

Algo así en el hilo por cliente:

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 ...
        }
    }
}

Entonces esto para el procesamiento:

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 ....
        }
    }
}

Dentro de la InputItemclase, también puedes incluir una referencia a cualquier estado del juego que necesite actualizarse. Dado que solo está cambiando el hilo de procesamiento, puede hacerlo sin ninguna sincronización.

Respuesta: 2

¿Cuál es la diferencia entre pasar en parámetro genérico alguna clase genérica con y sin su parámetro genérico? Ejemplo: clase genérica simple: clase pública Foo <T> {/*...*/} simple ...

Digamos que definí el siguiente servicio de servicio Thrift FileResource {binary get_file (1: string file_name)} Aquí está la implementación generada que no puedo entender pública ByteBuffer ...

Descubrí que la clase GeneralPath en Java solo proporciona métodos para verificar si un punto está dentro de una ruta general (para ser específico, un polígono con segmentos de línea recta). ¿Alguien sabe cómo ...

Estoy tratando de configurar un servidor de aplicaciones para ejecutar un sitio web simple y una aplicación cliente Java que necesita comunicarse de nuevo con un servidor Java. Lo que me gustaría hacer es lo siguiente: sitio web / web ...