Java TCP simple multi-user chat room

I. Description:

This example is a simple Java TCP multiplayer chat rooms, start the server, and then start the client, the client typing a user name, and then you can start chatting, type information, each online user will receive the appropriate information .
As shown below:
TCPChat.gif

II. Server-side code

  • ServerMain.java

    import java.io.*;
    
    public class ServerMain {
        public static void main(String[] args) {
            ChatServer server = new ChatServer();
            try {
                server.ServerStart();
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    }
  • ChatServer.java

    import java.io.*;
    import java.net.*;
    import java.util.HashMap;
    
    public class ChatServer {
        // 设定端口号
        private final int port = 12345;
        public static HashMap<ClientThread,Socket> clientMap = new HashMap<>();
        public static int onlineNum = 0;
    
        public static void ServerSendToAll(ClientThread thread,String msg) throws IOException {
            for (ClientThread t : clientMap.keySet()) {
                if (t.clientName.equals(thread.clientName)) {
                    Message.printMessage(thread.clientName + "说:" + msg);
                    continue;
                }
                t.objOutput.writeObject(new DataPacket(Message.CMD.SENDALL, thread.clientName + "说:" + msg));
            }
        }
    
        public static void ServerSendToAll(ClientThread thread) throws IOException {
            onlineNum++;
            // 服务端记录
            Message.printMessage(thread.clientName + "上线了,当前在线人数" + onlineNum + "人");
            // 群发
            for (ClientThread t : clientMap.keySet()) {
                if (t.login == true) {
                    t.objOutput.writeObject(new DataPacket(Message.CMD.LOGIN, "当前在线人数" + onlineNum + "人"));
                }   
            }
        }
    
        public void ServerStart() throws IOException {
            ServerSocket serverSocket = new ServerSocket(port);
    
            Message.printMessage("Server Start.");
            // 死循环等待客户端连接
            while (true) {
                // 每来一个客户端连接,保存Socket对象
                Socket clientSocket = serverSocket.accept();
    
                ClientThread client = new ClientThread(clientSocket);
                // 每连接一个客户端,创建一个对应的线程类
                Thread clientThread = new Thread(client);
    
                // 添加对象-Socket映射
                clientMap.put(client, clientSocket);
    
                // 启动线程
                clientThread.start();
            }
        }
    
    }
  • ClientThread.java

    import java.io.*;
    import java.net.*;
    
    /*
        线程类:处理每一个登录成功的客户端
    */
    public class ClientThread implements Runnable {
        // 保存每个客户端Socket
        private Socket client = null;
        public ObjectInputStream objInput = null;
        public ObjectOutputStream objOutput = null;
        public String clientName = null;
        public boolean login = false;
    
        public ClientThread(Socket client) {
            this.client = client;
            try {
                this.objInput = new ObjectInputStream(this.client.getInputStream());
                this.objOutput = new ObjectOutputStream(this.client.getOutputStream());
            } catch (IOException e) {
                Message.printLog(Message.logType.ERROR, "ClientThread:IOException!", true);
                e.printStackTrace();
            }
        }
    
        public int HandleReceiveMsg(Object data) throws IOException {
            DataPacket dataPacket = (DataPacket) data;
    
            switch (dataPacket.cmd) {
            case LOGIN:
                clientName = dataPacket.msg;
                login = true;
                ChatServer.ServerSendToAll(this);
                break;
            case SEND:
                // 收到消息,调用群发其他用户
                ChatServer.ServerSendToAll(this, dataPacket.msg);
                break;
            case SENDALL:
                // 收到其他用户群发的消息
                SendMessage(dataPacket);
                break;
            }
            return 0;
        }
    
        public void SendMessage(DataPacket data) throws IOException {
            this.objOutput.writeObject(data);
        }
    
        public Object ReceiveMessage() throws ClassNotFoundException, IOException {
            try {
                Object obj = this.objInput.readObject();
                return obj;
            } catch (EOFException e) {
    
            }
    
            return null;
        }
    
        @Override
        public void run() {
            try {
                Object data;
    
                while ((data = ReceiveMessage()) != null) {
                    HandleReceiveMsg(data);   
                }
            } catch (SocketException e) {
                login = false;
            } catch (IOException e) {
                Message.printLog(Message.logType.ERROR, "ClientThread-run:IOException!", true);
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                Message.printLog(Message.logType.ERROR, "ClientThread-run:ClassNotFoundException!", true);
                e.printStackTrace();
            } finally {
                // 用户断开连接
                if (login == false) {
                    // 打印信息
                    Message.printMessage(clientName + "下线了!");
                    // 从HashMap 移走映射
                    ChatServer.clientMap.remove(this);
                    // 释放资源
                    if (client != null) {
                        try {
                            client.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    
    }

III. The client code

  • ClientMain.java

    public class ClientMain {
        public static void main(String[] args) {
            ChatClient client = new ChatClient();
    
            client.ClientStart();
        }
    }
  • ChatClient.java

    import java.io.*;
    import java.net.*;
    import java.util.Scanner;
    
    public class ChatClient {
        private static final int port = 12345;
        private static String serverAddress = "localhost";
        private Socket client = null;
        private ObjectOutputStream objOutput = null;
        private ObjectInputStream objInput = null;
    
        public void SendMessage(DataPacket data) throws IOException {
            // 发送数据给服务器
            objOutput.writeObject(data);
        }
    
        public void ClientStart() {
            Scanner in = new Scanner(System.in);
            String userInput = null;
    
            // 用户输入用户名登录
            Message.printLog(Message.logType.INFO, "请输入你的用户名:", false);
            userInput = in.nextLine();
    
            // 连接服务器
            try {
                this.client = new Socket(serverAddress, port);
                // 服务器已连接
                if (this.client.isConnected()) {
                    // 获取输出流
                    this.objOutput = new ObjectOutputStream(this.client.getOutputStream());
                    // 获取输入流
                    this.objInput = new ObjectInputStream(this.client.getInputStream());
    
    
                    SendMessage(new DataPacket(Message.CMD.LOGIN, userInput));
    
                    // 创建一个线程用于接收信息
                    ClientReceiveMessageThread receiveMessage = new ClientReceiveMessageThread(this.objInput, userInput);
                    Thread receiveThread = new Thread(receiveMessage);
                    receiveThread.start();
    
                    // 这个线程用于发送信息
                    while (true) {
                        userInput = in.nextLine();
                        if (userInput != null) {
                            SendMessage(new DataPacket(Message.CMD.SEND, userInput));
                        } 
                    }
                }
            } catch (ConnectException e) {
                Message.printLog(Message.logType.ERROR, "ChatClient-ClientStart:ConnectException!", true);
                e.printStackTrace();
            } catch (SocketException e) {
                Message.printLog(Message.logType.ERROR, "服务器异常!", true);
                System.exit(0);
            } catch (IOException e) {
                Message.printLog(Message.logType.ERROR, "ChatClient-ClientStart:IOException!", true);
                e.printStackTrace();
            }
        }
    }
    
    class ClientReceiveMessageThread implements Runnable {
        private ObjectInputStream in = null;
        private String clientName = null;
    
        public ClientReceiveMessageThread(ObjectInputStream in, String name) {
            this.in = in;
            this.clientName = name;
        }
    
        public int HandleReceiveMsg(Object data) throws IOException {
            DataPacket dataPacket = (DataPacket) data;
    
            switch (dataPacket.cmd) {
            case LOGIN:
            case SEND:
            case SENDALL:
                Message.printMessage(dataPacket.msg);
                break;
            }
            return 0;
        }
    
        @Override
        public void run() {
            Object data;
    
            try {
                while ((data = in.readObject()) != null) {
                    HandleReceiveMsg(data);
                }
            } catch (EOFException e) {
    
            } catch (SocketException e) {
                Message.printLog(Message.logType.ERROR, "服务器异常!", true);
                System.exit(0);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
    
        }
    }

IV. Common class

  • Message.java

    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class Message {
        // 是否打开debug输出
        private static boolean debug = false;
        // 设定日期时间格式
        public static SimpleDateFormat dateFormat = new SimpleDateFormat("yyy-MM-dd hh:mm:ss");
    
        public static enum logType {
            ERROR,
            INFO,
            WARN,
            DEBUG,
        };
    
        public static enum CMD {
            LOGIN,
            SEND,
            SENDALL,
        }
    
        public static void printLog(logType type, String msg, boolean newLine) {
            if( debug == true || type != logType.DEBUG ) {
                StringBuilder sb = new StringBuilder(128);
                sb.append("[").append(type).append("]").append(msg);
                if (newLine)
                    System.out.println(sb);
                else 
                System.out.print(sb);
            }
    
        }
    
        public static void printMessage(String msg) {
            StringBuilder sb = new StringBuilder(1024);
            sb.append("[").append(dateFormat.format(new Date())).append("]").append(msg);
            System.out.println(sb);     
        }
    }
  • DataPacket.java

    import java.io.Serializable;
    
    public class DataPacket implements Serializable {
    
        /**
         *  自动生成的UID
         */
        private static final long serialVersionUID = -5366828169862565011L;
        public Message.CMD cmd;
        public String msg;
    
        public DataPacket(Message.CMD cmd, String msg) {
            this.cmd = cmd;
            this.msg = msg;
        }
    }

Guess you like

Origin www.cnblogs.com/LucasBlog/p/12104820.html