Create Instant Messaging ChatRoom in Java

        Instant Messaging apps like Wechat and Ding Talk are widely used in our personal life and business. Thus, creating a simple functional chatroom based on pure Java is kind of required ability for Java programmers, while it is also a good opportunity for us to practice multithreading programming as well as Java socket programming. This tutorial will divide the whole process into 3 major sub-steps to illustrate how to achieve this.

First step: 

The first step is to create a ChatRoom class, which will be our main class towards users.

public class ChatRoom {

    public ServerSocket serverSocket;
//这里主要运用了socket套接字的技术,实现的信息间的通讯
    public ChatRoom(ServerSocket serverSocket){
        this.serverSocket = serverSocket;
    }

public void startServe(){

            try{
                while(!serverSocket.isClosed()){
                //利用多线程技术,使用一个端口创建多线程Socket
                    Socket socket = serverSocket.accept();
                    System.out.println("client"+socket.getInetAddress());
                   //ClientHandle作为用户使用的service媒介,并处理服务器端的线程
                    ClientHandle clientHandle = new ClientHandle(socket);
                    Thread thread = new Thread(clientHandle);
                    thread.start();
                }
            } catch (IOException e) {
                closeServe();
                e.printStackTrace();
            }
        }


        public void closeServe(){
        if(serverSocket!=null){
            try {
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        }

public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(8848);
            ChatRoom chatRoom = new ChatRoom(serverSocket);
            chatRoom.startServe();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    }

        The core concept here is creating a server handler(The ClientHandle) in order to separate our server layer from the main chatroom class, as the server-side needs its own thread handling information exchange. 

Step two: Server-side ClientHandle

        Here is how to create a Server-side class. As mentioned before, the server-side needs its own thread for obtaining and broadcasting information to all other clients. Therefore, the ClientHandle class needs to implement Runnable interface.

        Another critical point is that we need to create an ArrayList or HashMap to contain all the ClientHandles. Sending messages to all ClientHandles in this list is how we could achieve broadcasting information. As all threads are sharing the same list, we have to label the list as "static";

public class ClientHandle implements Runnable{
    private Socket socket;
//创建的list应该是static的,不然多线程的情况下无法共用
    private static List<ClientHandle> list = new ArrayList<>();
//bufferReader用来读取信息
    private BufferedReader bufferedReader;
    private BufferedWriter bufferedWriter;
    private String user;

    public ClientHandle(Socket socket){
        this.socket = socket;
        try {
            this.bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            this.bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
           
            user = bufferedReader.readLine();
            list.add(this);
            bufferedWriter.write("欢迎光临:"+user);
//newLine告诉计算机已完成输入
            bufferedWriter.newLine();
            bufferedWriter.flush();
            broadCast(user+"到来聊天室");
        } catch (IOException e) {
            closeEverything(socket,bufferedWriter,bufferedReader);
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        String message;
        while(!socket.isClosed()){
            try {
                message = bufferedReader.readLine();
//broadCast使用forEach来将信息传递给每个元素
                broadCast(message);
            } catch (IOException e) {
                closeEverything(socket,bufferedWriter,bufferedReader);
            }
        }
    }

    public void broadCast(String message){
        for(ClientHandle clientHandle : list){
            if(!clientHandle.getUser().equals(this.user)) {
//这里判断是除开自己的Client线程不再重复发送信息
                try {
                    clientHandle.bufferedWriter.write(message);
                    clientHandle.bufferedWriter.newLine();
                    clientHandle.bufferedWriter.flush();
                } catch (IOException e) {
                    closeEverything(socket, bufferedWriter, bufferedReader);
                    e.printStackTrace();
                }
            }
        }
    }

    public void remove(){
//在删除用户的时候要把用户从集合中删除掉
        list.remove(this);
        broadCast("Server:"+user+"已离开!");
    }

    public void closeEverything(Socket socket, BufferedWriter writer, BufferedReader reader){
        remove();
        if(socket!=null && writer!=null && reader!=null){
            try {
                writer.close();
                reader.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

 

Step 3: Create Client Classes

Last but not least, the Client class is our user class. Here, the major point that we need to remember is that the sending and receiving methods should be separated. Meanwhile,  the sending and receiving methods have their own thread in one client.

public class Client {
    private Socket socket;
    private BufferedReader bufferedReader;
    private BufferedWriter bufferedWriter;
    private String user;

    public Client(Socket socket, String user){
        this.socket = socket;
        this.user =user;
        try {
            this.bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            this.bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        } catch (IOException e) {
            closeEverything(socket,bufferedWriter,bufferedReader);
            e.printStackTrace();
        }



    }

    public void sendMessage(){
//发出信息有单独的线程
        try {
            bufferedWriter.write(user);
            bufferedWriter.newLine();
            bufferedWriter.flush();
            Scanner scanner = new Scanner(System.in);
            while (!socket.isClosed()){
                String message = scanner.nextLine();
                bufferedWriter.write(user+":"+message);
                bufferedWriter.newLine();
                bufferedWriter.flush();
            }
        } catch (IOException e) {
            closeEverything(socket,bufferedWriter,bufferedReader);
            e.printStackTrace();
        }
    }

    public void listen(){
        //接收信息也有单独的线程
        new Thread( new Runnable() {
            @Override
            public void run() {
                String message;
                    try {
                        while(socket.isConnected()) {
                            message = bufferedReader.readLine();
                            System.out.println(message);
                        }
                    } catch (IOException e) {
                        closeEverything(socket,bufferedWriter,bufferedReader);
                        e.printStackTrace();}
            }
        }).start();
    }

    public void closeEverything(Socket socket, BufferedWriter writer, BufferedReader reader){
        if(socket!=null && writer!=null && reader!=null){
            try {
                socket.close();
                writer.close();
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入你的用户名:");
        String user = scanner.nextLine();
        try {
            Socket socket = new Socket("127.0.0.1",8848);
            Client client = new Client(socket,user);
            client.listen();
            client.sendMessage();



        } catch (IOException e) {
            e.printStackTrace();
        }


    }

}

Conclusion

        There are two critical points we need to focus on for this project:

        1. The ClientHandle class should has its own thread while each Client class should have separated sending and listening method threads.

        2.All ClientHandle classes should share one static list.

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值