Java - Chat async

Asked

Viewed 310 times

2

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

I managed to make a public chat using sockets(Netty), but I got to the following problem:

  1. The server sends messages to everyone, rather than a specific group. (How to select the recipient?)

If you have an example project, thank you.

  • Your question is extremely general, it’s difficult to answer with little information. Have you used any specific protocol to communicate with customers? With TCP and UDP sockets it is quite trivial to define a destination address.

  • @Roney I’m wearing it Netty, but I don’t know if it’s the best way to communicate between clients. That’s why I want to know which is the best architecture to chat.

1 answer

1

I don’t know Netty, but from the link you passed, I believe he’s sending 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 this client will receive the message.

Anyway, I believe that Netty offers a number of features that you shouldn’t need at the moment. I would start by taking a look at java Docs tutorials. There is a ready example of server and client.

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

Here’s an experience of mine, based on the javadocs tutorial.

I included a ArrayList<> to save the users who connect:

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.

Example of the server:

ServidorChat

Example of customers (in my version, x <msg> sends message to all):

ClienteChat0

Already <número> <msg> sends the message to the user with this number:

ClienteChat1 ClienteChat2

Servidorchat.java:

import java.net.*;
import java.io.*;

public class ServidorChat {

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

        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());

    }

}

Chatcliente.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());

    }
}

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

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 set aside, and many things need to be implemented. For example:

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

  2. There is no deal for connection break - if a user disconnects, it will start giving error too (I removed to reduce the code size).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.