Java Socket simulation chat room

  • 2021-10-24 22:45:37
  • OfStack

Java Socket simulation to achieve a chat room, the realization of the basic private chat and group chat. Divided into server-side and client-side, I will introduce the steps of implementation under 1 below.

Server side

The server side is the core of the chat room, which is mainly used to deal with the request of the client. First, look at the main method of the server side under 1:


public static void main(String[] args) {
        try {
            ExecutorService executorService = Executors.newFixedThreadPool(100);// Maximum capacity 100 Client chat 
            ServerSocket serverSocket = new ServerSocket(6655);// Eavesdropping 6655 No. port 
            for (int i = 0; i < 100; i++) {
                Socket client = serverSocket.accept();
                System.out.println(" There is a new user connection  " + client.getInetAddress() +
                        client.getPort());
                executorService.execute(new ExecuteClientThread(client));
            }
            executorService.shutdown();
            serverSocket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

First of all, I created a fixed size of 100 thread pool, the implementation of this chat room is a server thread corresponding to a client thread, that is to say, the size of the thread pool is the maximum number of people chatting at the same time. The execution order of the server is as follows:

1. Listen to the port and wait for the client to connect

2. If a client is connected to the listening port, return the client's Socket via the accept () method, and start a new server thread in the thread pool to "communicate" with the client just connected.

3. Inject the received Socket construct of the client into the newly started server thread, so that the server thread can obtain the corresponding stream of the client.

At this point, the server has successfully connected with the client. Now let's look at how the server thread handles the client's request. First, let's go to the server code


private static Map<String, Socket> clientMap = new ConcurrentHashMap<>();// Store all user information 
 
    static class ExecuteClientThread implements Runnable {
        private Socket client;// Every 1 Server threads correspond to 1 Client threads 
        ExecuteClientThread(Socket client) {
            this.client = client;
        }
......

Line 1 of the code creates an ConcurrentHashmap, which is not in a thread, but the static property of the server, and is used to store the information of all clients. Because the client has a name and Socket, it is stored in K-value mode, and the user name is Key. Considering the reason of thread safety, ConcurrentHashmap is adopted to ensure thread safety.

Next is the Socket of the connected client that has just been constructed, and we can get the input and output streams through this Socket.

Then it is the run method executed by the thread of the server, and the specific code is directly looked at. There are comments, so we won't explain 11. The following is all the server-side code


import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
 
 
public class Main {
 
 
    private static Map<String, Socket> clientMap = new ConcurrentHashMap<>();//存储所有的用户信息
 
    static class ExecuteClientThread implements Runnable {
        private Socket client;//每1个服务器线程对应1个客户端线程
        ExecuteClientThread(Socket client) {
            this.client = client;
        }
 
        @Override
        public void run() {
            boolean Flag = true;//防止1个客户端多次注册所做的标记位置
            try {
                PrintStream PrintToCilent = new PrintStream(client.getOutputStream());//服务器向用户输出1些提示信息
 
 
                Scanner scanner = new Scanner(client.getInputStream());
                String str = null;//用户外部的输入信息
                while (true) {
                    if (scanner.hasNext()) {
                        str = scanner.next();//外部的用户输出
 
                        Pattern pattern = Pattern.compile("\r");//排除特殊符号
                        Matcher matcher = pattern.matcher(str);
                        str = matcher.replaceAll("");
 
                        if (str.startsWith("userName")) {
                            String userName = str.split(":")[1];
                            userRegist(userName, client, Flag);
                            Flag = false;
                        }
                        // 群聊流程
                        else if (str.startsWith("G:")) {
                            PrintToCilent.println("已进入群聊模式!");
                            groupChat(scanner,client);
                        }
                        // 私聊流程
                        else if (str.startsWith("P")) {//模式
                            String userName = str.split("-")[1];
                            PrintToCilent.println("已经进入与"+userName+"的私聊");
 
                            privateChat(scanner,userName);
                        }
                        // 用户退出
                        else if (str.contains("byebye")) {
                            String userName = null;
                            for (String getKey:clientMap.keySet()) {
                                if (clientMap.get(getKey).equals(client)) {
                                    userName = getKey;
                                }
                            }
 
                            System.out.println("用户"+userName+"下线了..");
                            clientMap.remove(userName);//将此实例从map中移除
                        }
                    }
                }
 
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
       
        private void userRegist(String userName, Socket client, boolean Flag) throws IOException {
            PrintStream PrintToCilent = new PrintStream(client.getOutputStream());//服务器向用户输出1些提示信息
            if(Flag) {
                System.out.println("用户" + userName + "上线了!");
 
                clientMap.put(userName, client);//把用户加入储存map
                System.out.println("当前群聊人数为" + (clientMap.size()) + "人");
                PrintToCilent.println("注册成功!");
            }else {
                PrintToCilent.println("警告:1个客户端只能注册1个用户!");
            }
        }
     
        private void groupChat(Scanner scanner,Socket client) throws IOException {
            // 取出clientMap中所有客户端Socket,然后遍历1遍
            // 分别取得每个Socket的输出流向每个客户端输出
            PrintStream PrintToClient = new PrintStream(client.getOutputStream());//在群聊的时候服务器向客户端发送数据
            boolean ExitFlag = false;
 
            Set<Map.Entry<String, Socket>> entrySet =
                    clientMap.entrySet();
 
            String userName = null;
            for (Map.Entry<String, Socket> socketEntry : entrySet) {//获得:是哪个用户说的话
                if (socketEntry.getValue() == client) {
                    userName = socketEntry.getKey();//发出信息的用户
                }
            }
            String msg = null;
 
            while (true) {
                if (scanner.hasNext()) {
                    msg = scanner.next();
                    if("exit".equals(msg)){//如果用户退出了
                        for(Map.Entry<String,Socket> stringSocketEntry : entrySet){
                            new PrintStream(stringSocketEntry.getValue().getOutputStream(),true).println("用户"+userName+"刚刚退出了群聊!!");//给所有人发退出群聊的消息
                        }
                        return;
                    }
 
 
                    for (Map.Entry<String, Socket> stringSocketEntry : entrySet) {//遍历用户的map,获取所有用户的Socket
                        try {
                            Socket socket = stringSocketEntry.getValue();
                            PrintStream ps = new PrintStream(socket.getOutputStream(), true);
 
                            ps.println("群聊:用户" + userName + "说: " + msg);//给每个用户发消息
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
 
                }
            }
 
        }
        private void privateChat(Scanner scanner, String privatepeopleName) throws IOException {
 
            Socket privateUser = clientMap.get(privatepeopleName);
            PrintStream ps = new PrintStream(privateUser.getOutputStream());//拿到私聊对象的输出流
            PrintStream PrintToClient = new PrintStream(client.getOutputStream());//拿到当前客户端的输出流
            String Message = null;
            String MyName = null;
            Set<Map.Entry<String,Socket>> set = clientMap.entrySet();
            for(Map.Entry<String,Socket> value : set){
                if(value.getValue() == client){
                    MyName = value.getKey();
                    break;
                }
            }
 
            while (true) {
                if(scanner.hasNext()) {
                    Message = scanner.next();
                    if ("exit".equals(Message)){//如果用户输入了退出
                        PrintToClient.println("已退出和"+privatepeopleName+"的私聊");
                        ps.println("对方已经退出了私聊");
                        break;
                    }
                    ps.println(MyName+"说"+Message);//如果用户没有退出,向私聊对象发送消息
                }
            }
 
 
        }
 
 
    }
 
    public static void main(String[] args) {
        try {
            ExecutorService executorService = Executors.newFixedThreadPool(100);//最多容纳100个客户端聊天
            ServerSocket serverSocket = new ServerSocket(6655);
            for (int i = 0; i < 100; i++) {
                Socket client = serverSocket.accept();
                System.out.println("有新的用户连接 " + client.getInetAddress() +
                        client.getPort());
                executorService.execute(new ExecuteClientThread(client));
            }
            executorService.shutdown();
            serverSocket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Then there is the client code, which is relatively simple: it is divided into two threads, one thread is used to receive data from the server, and one thread is used to send data to the server. I'll just go straight to the code, which has comments.


import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
 
 
class ExcuteServerInPut implements Runnable{// Receive data from the server 
    private Socket ToServer;
 
    ExcuteServerInPut(Socket ToServer){
        this.ToServer = ToServer;
    }
 
    @Override
    public void run() {
        try {
            Scanner scanner = new Scanner(ToServer.getInputStream());
               while (scanner.hasNext()){
                System.out.println(scanner.nextLine());
            }
            scanner.close();
            ToServer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 
class ExcuteServerOutPut implements Runnable{// Send data to the server 
 
    private Socket Socket;
    ExcuteServerOutPut(Socket Socket){
        this.Socket = Socket;
    }
 
    @Override
    public void run() {
        try {
            PrintStream printStream = new PrintStream(Socket.getOutputStream());
            Scanner scanner = new Scanner(System.in);
            scanner.useDelimiter("\n");
            System.out.println("*****************************************");
            System.out.println("*** User registration :useerName: Same account name ( Only 1 Times )***");
            System.out.println("*** Enter group chat :G:            Quit group chat :exit***");
            System.out.println("*** Private chat :P- User name           Quit private chat :exit***");
            System.out.println("*********** Quit the chat room :byebye*************");
            while (true){
                if(scanner.hasNext()) {
                    String string = scanner.next();
                    printStream.println(string);
                    if ("byebye".equals(string)) {
                        System.out.println(" Quit! ");
                        printStream.close();
                        scanner.close();
                        break;
                    }
                }
 
            }
 
            Socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 
 
public class Main {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 6655);
        ExcuteServerInPut excuteServerInPut = new ExcuteServerInPut(socket);
        ExcuteServerOutPut excuteServerOutPut = new ExcuteServerOutPut(socket);
        new Thread(excuteServerInPut).start();
        new Thread(excuteServerOutPut).start();
        }
}

I will make some improvements in the follow-up, hoping to help everyone


Related articles: