Java - Chat async

2

I want to implement a java chat, which works asynchronously, and wanted to know the best architecture to do that.

I was able to do a public chat using sockets (Netty), but I came up with the following problem:

  • The server sends the messages to everyone, instead of a specific group. (How to select the recipient?)
  • If you have any sample projects, thank you.

        
    asked by anonymous 03.08.2015 / 00:18

    1 answer

    1

    I do not know Netty, but from the link you've been through, I believe he's sending the messages to everyone in this method:

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
    // Send the received message to all channels but the current one.
    
        for (Channel c: channels) {
            if (c != ctx.channel()) {
                c.writeAndFlush("[" + ctx.channel().remoteAddress() + "] " + msg + '\n');
                } else {
                    c.writeAndFlush("[you] " + msg + '\n');
                }
            }
    }
    

    And, apparently, every Channel represents a user connected to the server. If you choose only one of them, only that client will receive the message.

    In any case, I believe Netty offers a number of features that you should not need at the moment. I'd start by taking a look at the java docs tutorials . There is a ready example of server and client .

    Although they are very simple, with some modifications, it is possible to transform them into a complete chat program, with separate messages for each user.

    Here is my experience, based on the javadocs tutorial.

    I've included ArrayList<> to save connecting users:

    public static ArrayList<SCThread> lista = new ArrayList<SCThread>();
    

    And when the server receives a message, I loop like Netty's, but this time looking for the recipient of the message.

    Server example:

    Exampleclients(inmyversion,x<msg>sendsmessagetoeveryone):

    Already<número><msg>sendsthemessagetotheuserwiththisnumber:

    ServerChat.java:

    importjava.net.*;importjava.io.*;publicclassServidorChat{publicstaticvoidmain(String[]args)throwsIOException{if(args.length!=1){System.err.println("Utilizacao: java ServidorChat <porta>");
                System.exit(1);
            }
    
            System.out.println("ServidorChat");
            int porta = Integer.parseInt(args[0]);
            boolean portaAberta = true;
    
            try (ServerSocket servidorSocket = new ServerSocket(porta)) {
                while (portaAberta) {
                    SCThread s = new SCThread(servidorSocket.accept());
                    s.start();
                    Usuarios.adicionar(s);
                }
            } catch (IOException e) {
                System.err.println("Erro ao abrir a porta " + porta);
                System.exit(-1);
            }
        }
    
    }
    

    SCThread.java:

    import java.net.*;
    import java.io.*;
    
    public class SCThread extends Thread {
        private Socket socket = null;
    
        public SCThread(Socket socket) {
            super("ServidorChatThread");
            this.socket = socket;
        }
    
        public void run() {
    
            try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));) {
                String inputLine;
    
                while ((inputLine = in.readLine()) != null) {
    
                    for (int i = 0; i < Usuarios.lista.size(); i++) {
    
                        if (inputLine.startsWith(i + " ")) {
                            Usuarios.lista.get(i).envia(this.getName() + " te diz: " + inputLine.substring(2));
                        }
                    }
    
                    if (inputLine.startsWith("x ")) {
    
                        for (SCThread usuario : Usuarios.lista) {
    
                            if (usuario != this) {
                                usuario.envia(this.getName() + ": " + inputLine.substring(2));
                            }
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public void envia(String msg) throws IOException {
            socket.getOutputStream().write((msg + "\n").getBytes());
    
        }
    
    }
    

    ChatClient.java

    import java.io.*;
    import java.net.*;
    import java.util.Scanner;
    
    public class ChatCliente {
    
        static Socket s;
    
        public static void main(String[] args) throws IOException {
    
            if (args.length != 2) {
                System.err.println("Utilizacao: java ChatCliente <endereco> <porta>");
                System.exit(1);
            }
    
            String hostName = args[0];
            int portNumber = Integer.parseInt(args[1]);
    
            s = new Socket(hostName, portNumber);
    
            ClienteThread cT = new ClienteThread(s);
            cT.start();
    
            Scanner scan = new Scanner(System.in);
    
            while (scan.hasNextLine()) {
    
                enviar(scan.nextLine() + "\n");
    
            }
            scan.close();
    
        }
    
        public static void enviar(String str) throws IOException {
    
            s.getOutputStream().write(str.getBytes());
    
        }
    }
    

    ClientThread.java

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.Socket;
    
    public class ClienteThread extends Thread {
    
        BufferedReader in;
    
        public ClienteThread(Socket s) throws IOException {
    
            in = new BufferedReader(new InputStreamReader(s.getInputStream()));
        }
    
        String mensagem;
    
        public void run() {
    
            try {
                while ((mensagem = in.readLine()) != null)
    
                    System.out.println(mensagem);
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    
    }
    

    Users.java

    import java.io.IOException;
    import java.util.ArrayList;
    
    public class Usuarios {
    
        public static ArrayList<SCThread> lista = new ArrayList<SCThread>();
    
        public static void adicionar(SCThread u) throws IOException {
    
            lista.add(u);
            u.setName("Usuario " + (lista.size() - 1));
            u.envia("Servidor: Voce eh o " + u.getName());
            System.out.println("Quantidade de usuarios: " + lista.size());
        }
    
    }
    

    Note that this is just a general idea. Many steps have been put aside, and many things need to be implemented. For example:

  • This code is not thread safe (if many users connect at the same time, it will hang). Most notable is ArrayList<> that should be replaced, as said here .

  • There is no such thing as connection breakdown - if a user disconnects, it will start to give error as well (I've removed it to reduce the size of the code).

  • 06.08.2015 / 12:34