cómo detener el cliente de chat multiproceso

Estoy tratando de crear un cliente-servidor de chat multiproceso utilizando Java. Estoy usando este tutorial como inicio: http://pguides.net/java-tutorial/java-tcp-clientserver-chat/

Quiero que el cliente se detenga cuando ingrese la cadena "salir", pero no entiendo cómo podría hacerlo. Además, necesito eliminar el cliente de la lista de nicks conectados cuando el cliente se desconecta.

Servidor

/* ChatServer.java */
import java.net.ServerSocket;
import java.net.Socket;

import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;

import java.util.Hashtable;

public class ChatServer {
    private static int port = 1001; 

    public static void main (String[] args) throws IOException {

        ServerSocket server = null;
        try {
            server = new ServerSocket(port);
        } catch (IOException e) {
            System.err.println("Could not listen on port: " + port);
            System.err.println(e);
            System.exit(1);
        }

        Socket client = null;
        while(true) {
            try {
                client = server.accept();
            } catch (IOException e) {
                System.err.println("Accept failed.");
                System.err.println(e);
                System.exit(1);
            }
            /* start a new thread to handle this client */
            Thread t = new Thread(new ClientConn(client));
            t.start();
        }
       }
}

class ChatServerProtocol {
    private String nick;
    private ClientConn conn;

    private static Hashtable<String, ClientConn> nicks = new Hashtable<String, ClientConn>();

    private static final String msg_OK = "OK";
    private static final String msg_INVALID = "INVALID COMMAND";
    private static final String msg_SEND_FAILED = "FAILED TO SEND";

    private static boolean add_nick(String nick, ClientConn c) {
        if (nicks.containsKey(nick)) {
            return false;
        } else {
            nicks.put(nick, c);
            return true;
        }
    }

    private static boolean remove_nick(String nick, ClientConn c) {
        if (!(nicks.containsKey(nick))) {
            return false;
        } else {
            nicks.remove(nick);
            return true;
        }
    }

    public ChatServerProtocol(ClientConn c) throws IOException {
        nick = null;
        conn = c;
    }


    private boolean sendMsg(String recipient, String msg) {
        if (nicks.containsKey(recipient)) {
            ClientConn c = nicks.get(recipient);
            c.sendMsg(nick + ": " + msg);
            return true;
        } else {
            return false;
        }
    }


    public String process(String msg) {
        if (msg.startswith("Nick"){
        String output = "";
        if(add_nick(tryauthor, this.conn)) {
            this.nick = tryauthor;
            output = "Welcome "+tryauthor;
            } else {
                    output = "Nick already in";
                }
            }

        }
        else if (msg.startsWith("msg")) {
            String[] msg_parts = msg.split(":");
            for(int i=0; i<msg_parts.length; i++){
                System.out.println(msg_parts[i]);
            }
            String msg_type = msg_parts[0];
            if(msg_type.equals("msg")) {
                if(msg_parts.length < 3) output = msg_INVALID;
                if(sendMsg(msg_parts[1], msg_parts[2])) output = msg_OK;
                else output = msg_SEND_FAILED;
            } else {
                output = msg_INVALID;
            }
        }

        return output;
     }
    }

class ClientConn implements Runnable {
    private Socket client;
    private BufferedReader in = null;
    private PrintWriter out = null;

    public ClientConn(Socket client) {
        this.client = client;
        try {
            /* obtain an input stream to this client ... */
            in = new BufferedReader(new InputStreamReader(client.getInputStream()));
            /* ... and an output stream to the same client */
            out = new PrintWriter(client.getOutputStream(), true);
        } catch (IOException e) {
            System.err.println(e);
            return;
        }
    }

    public void run() {
        String msg, response;

        try {
             ChatServerProtocol protocol = new ChatServerProtocol(this);
            /* loop reading lines from the client which are processed 
             * according to our protocol and the resulting response is 
             * sent back to the client */
            while ((msg = in.readLine()) != "quit\r\n") {
                response = protocol.process(msg);
                out.println("SERVER: " + response);
            }
            this.close();
        } catch (IOException e) {
            System.err.println(e);
        }
    }

    public void sendMsg(String msg) {
        out.println(msg);
     }

    public void close() throws IOException {
        in.close();
        out.close();
        client.close();
    }

}

Cliente

/* ChatClient.java */
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

public class ChatClient {
private static int port = 1001; 
private static String host = "localhost"; 

private static BufferedReader stdIn;

public static void main (String[] args) throws IOException {

    Socket server = null;

    try {
        server = new Socket(host, port);
    } catch (UnknownHostException e) {
        System.err.println(e);
        System.exit(1);
    }

    stdIn = new BufferedReader(new InputStreamReader(System.in));

    PrintWriter out = new PrintWriter(server.getOutputStream(), true);
    BufferedReader in = new BufferedReader(new InputStreamReader(server.getInputStream()));

    System.out.print("Nick: ");
    String auth = stdIn.readLine();
    out.println("Nick: " + auth);
    String serverResponse = in.readLine();
    System.out.println(serverResponse);

    if (serverResponse.startsWith("SERVER: welcome")) {
         /* create a thread to asyncronously read messages from the server */
        ServerConn sc = new ServerConn(server);
        Thread t = new Thread(sc);
        t.start();

        String msg;
        /* loop reading messages from stdin and sending them to the server */
        while ((msg = stdIn.readLine()) != "quit\r\n") {
            out.println(msg);
        }
        sc.close();
        System.out.println("Exit.");
        System.out.println("---Client Error---");
    }
    else {
        System.out.println("Exit.");
        System.out.println("---Client Error---");
    }


  }
}

class ServerConn implements Runnable {
    private BufferedReader in = null;
    private Socket server;

    public ServerConn(Socket s) throws IOException {
        server = s;
        in = new BufferedReader(new InputStreamReader(s.getInputStream()));
    }

    public void run() {
        String msg;
        try {
            /* loop reading messages from the server and show them 
             * on stdout */
             while ((msg = in.readLine()) != "quit\r\n") {
                System.out.println(msg);
             }
             this.close();
        } catch (IOException e) {
            System.err.println(e);
        }
      }

    public void close() throws IOException {
        in.close();
        server.close();
    }

}

¿Dónde y cómo debo cerrar la conexión?

Respuesta 1

ahora el cliente solo puede autenticarse si su nombre es parte de un gráfico que he creado antes.

Esto parece estar escrito en el código. En su Process()método, busca el autor en el authorsgraphy, si no lo encuentra, devuelve un error. ¿No es esto lo que pretendías? Si no se encuentra el autor, ¿debería agregarlo en su lugar? Tal vez la add_nice()llamada debería estar en el elsesi no los ha encontrado junto con alguna forma de agregar al autor al authorsgraph?

Caminar sobre el manejo de una nueva conexión en un depurador podría ayudarlo aquí. El uso liberal de los System.out.println()mensajes también podría ser útil.

Quiero que el cliente se detenga cuando ingrese la cadena "salir", pero no entiendo cómo podría hacerlo.

Bueno, este código tiene un error. Debe usar .equals()para verificar la Stringigualdad. !=solo prueba msgque no tiene la misma String referencia , no el mismo contenido de cadena :

// can't use != on a `String` to check contents
while ((msg = stdIn.readLine()) != "quit\r\n") {

Debería ser:

while (true) {
   msg = stdIn.readLine();
   if (msg == null || msg.equals("quit")) {
      break;
   }
   ...

Observe también que no estoy marcando el "\ r \ n". El readLine()método devuelve la cadena (para citar de los javadocs) "sin incluir ningún carácter de terminación de línea". Además, debe probar nullen caso de que el zócalo esté cerrado. También tiene 2 lugares en su código de cliente con el mismo error.

Necesito eliminar al cliente de la lista de nicks conectados cuando el cliente se desconecta.

Su whileciclo anterior se cerrará si el socket del cliente está cerrado o entran "quit". Entonces llamas close(). Después de llamar close(), puede llamar protocol.remove_nicks()para eliminarlo del bucle. Pero no tienes el "nick" Stringallí.

Realmente, mantener la lista del nicks interior ChatServerProtocolpuede no ser el lugar adecuado para ello. Yo mismo lo incluiría ChatServerProtocolen la ClientConnclase ya que hay uno de cada por conexión. De cualquier manera, algún objeto necesita almacenar la "nick"cadena con la que el autor inició sesión y luego llamar remove_nick()con esa cadena después de que "quit"se ingresa o se cierra la conexión.

Por último, el uso de HashTableha quedado en desuso desde Java 5. Yo usaría en su Collections.synchronizedMap(new HashMap<...>())lugar.

Espero que esto ayude.

Respuesta: 2

Cada ejemplo que puedo encontrar pasa por crear una tabla sin una interfaz gráfica de usuario o explica cómo llenar desde una base de datos. Debo estar perdiendo algo simple, pero esto es lo que hasta ahora he basado en ...

Tengo muchos problemas para crear un archivo .jar. Cada vez que intento crear uno, aparece una ventana de error y dice que no se puede encontrar el inicio de clase principal. (Mi clase principal se llama Inicio) Yo ...

Hola tengo un gran problema Estoy haciendo un programa Java y tengo que llamar a un archivo exe en una carpeta que tiene espacios en blanco. Este programa también tiene 2 argumentos que siempre tienen espacios en blanco en la ruta. Ejemplo: ...

Me gustaría saber cómo puedo establecer, por ejemplo, una barra de progreso de visibilidad desde varios Fragmentos. clase MyActivity extiende FragmentActivity {public setProgressBar (boolean toggle) {progressBar ....