Java implements the functions of chat, group chat and sensitive vocabulary filtering based on Socket

Posted by ybinds on Wed, 02 Feb 2022 04:44:07 +0100

First of all, I wrote this code a long time ago, and then there were many places I didn't understand at that time. Now let's take a look at this code. I really feel ugly and want to change it, but it's really hard to change it
Therefore, writing code and specification are really important.

Functions realized:

  1. User private chat
  2. Group chat function: enter or leave the group, send messages and view group chat
  3. View your own message records
  4. Through the file stream, set sensitive word filtering (dictionary tree is also used here...) but I'm still a little unskilled
  5. Offline, logout

Insufficient:
emmm, in fact, there are too many deficiencies.
First of all, the function is not completely perfect, especially the group chat function (but I think the realization of the later function is of little significance)
Then, writing code is not standard.
It doesn't use Java object-oriented knowledge. It only stores the user's nickname and doesn't set a password
You should also set a to send the data in the cache after the user goes online.
The data was not saved. After closing the program, the data disappeared
At the beginning, I didn't know how to use the collection. Later, I found that putting a List (actually an object) in the collection can store a lot of things
In a word, we should write more code and learn more knowledge at the same time!!!

Start coding!

directory structure


If I'm here, put my four classes under test1 package.

In fact, a lot of if else is used here... Then, I want to call the corresponding method statements here. You need to input the corresponding Chinese prefix first, which is very troublesome... I suggest you use the loop and prompt the user to enter the corresponding instruction each time.

TCPServer

The first is to start the server in the county. If it is not started, it will report an error!!!

package test1;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TCPServer {

    public static void main(String[] args) {
        TCPServer server = new TCPServer();
        server.start();
    }

    /**
     * Create a thread pool to manage the connection threads of the client
     * Avoid excessive waste of system resources
     */
    private ServerSocket serverSocket;
    private ExecutorService exec;
    /**
     * Store user nickname and print stream
     */
    private Map<String, PrintWriter> storeInfo;
    /**
     * Store private chat information between clients
     */
    private Map<String, LinkedList<String>> storeMessages;
    /**
     * Message that the user is not online [I don't implement it here]
     */
    private Map<String, String> waitMessages;

    /**
     * Group K: group name, Value: nickname collection of personnel
     */
    Map<String, LinkedList<String>> aGroup = new LinkedHashMap<>();

    public TCPServer() {//constructor 
        try {
            serverSocket = new ServerSocket(9999);
            storeInfo = new ConcurrentHashMap<String, PrintWriter>();
            exec = Executors.newCachedThreadPool();//Create thread pool
            storeMessages = new ConcurrentHashMap<String, LinkedList<String>>();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start() {
        try {
            while (true) {
                System.out.println("The server waits for the client to connect... ... ");
                Socket socket = serverSocket.accept();//Only when a customer appears will accept()
                System.out.println("Client:“" + socket.getInetAddress().getHostAddress() + ""Connection succeeded! ");
                //Start a thread to process the request of the client, so that you can listen to the connection of the next client again
                //Each time, a server Socket is bound to a client. At the same time, the server opens the request input stream of the listening client
                exec.execute(new ListenerClient(socket)); //Allocate threads through the thread pool to listen to the client. If a client appears, create a new thread
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Create internal classes to get nicknames
     * Listening client
     * The thread body is used to process the message of a given client, receive each string sent by the client circularly, and output it to the console
     */
    class ListenerClient implements Runnable {
        private Socket socket;
        private String name;

        public ListenerClient(Socket socket) {
            this.socket = socket;
        }

        /**
         * Methods of managing nicknames
         */
        private String getName() throws Exception {
            //The input stream of the server reads the nickname output stream sent by the client
            BufferedReader bReader = new BufferedReader(
                    new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
            //Send the nickname output of the server to the client through the verification
            PrintWriter ipw = new PrintWriter(
                    new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true);
            //Read the nickname sent by the client
            while (true) {
                String nameString = bReader.readLine();
                if ((nameString.trim().length() == 0) || storeInfo.containsKey(nameString)) {
                    ipw.println("FAIL");//Send to client
                } else {
                    ipw.println("OK");
                    return nameString;
                }
            }
        }

        /**
         * Listener method 
         * The output stream of the client is obtained through the Socket of the client and used to send messages to the client
         */
        @Override
        public void run() {
            try {
                PrintWriter pw = new PrintWriter(
                        new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true);
                name = getName();
                putIn(name, pw, storeInfo);//Store the customer's nickname and the content said by the server into the shared collection HashMap storeinfo
                Thread.sleep(100);
                // The server notifies all clients that a user is online (sent in groups)
                sendToAll("[System notification] "" + name + ""Online");
                System.out.println("[System notification] "" + name + ""Online");
                /* Read client
                 * Get the input stream through the Socket of the client and read the information sent by the client
                 */
                BufferedReader bReader = new BufferedReader(
                        new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));

                String msgString = null;//Use msgString to get the input from the client
                while ((msgString = bReader.readLine()) != null) {
                    LinkedList<String> msgList = storeMessages.get(name);
                    if (msgList == null) {
                        msgList = new LinkedList<String>();
                    }
                    // Check whether it is private chat (Format: @ nickname: content)
                    if (msgString.startsWith("@")) {
                        int index = msgString.indexOf(":");//@deng:xxx (content after colon)
                        if (index == -1) {
                            index = msgString.indexOf(": ");
                        }
                        if (index >= 0) {
                            String theName = msgString.substring(1, index);//Get nickname
                            String info = msgString.substring(index + 1);//Get sent content
                            if (isBlank(info)) {
                                pw.println("[System prompt]: Messages sent to friends cannot be empty!");
                            }
                            info = """ + name + "": " + info;
                            //Send out private chat information
                            boolean b = sendToSomeone(theName, isIllegal(info));
                            if (!b) {
//Return to the original user: message sending failed, no one found
                                pw.println("[System prompt]: The specified user was not found“" + theName + "",Message sending failed");
                            }
                            msgList.add(msgString);
                            storeMessages.put(name, msgList);
                            continue;
                        }
                    } else if (msgString.startsWith("New group:") || msgString.startsWith("New group:")) {
                        creatGroup(msgString, name);
                        continue;
                    } else if (msgString.contains("Group invitation:") || msgString.contains("Group invitation:")) {
                        groupInvite(msgString, name);
                        continue;
                    } else if (msgString.startsWith("withdraw from a group:") || msgString.startsWith("withdraw from a group:")) {
                        String groupName = msgString.substring(3);
                        exitGroup(groupName, name);
                        continue;
                    } else if (msgString.startsWith("I want to join the group:") || msgString.startsWith("I want to join the group:") ) {
                        String groupName = msgString.substring(5);
                        acceptGroup(groupName, name);
                        continue;
                    } else if (msgString.contains("Check the group chat I joined")) {
                        pw.println("The group chat I joined is"+showMyGroups(name));
                        continue;
                    } else if ("View message record".equals(msgString)) {
                        printOnlineUser(name);
                        printAllMessages(name);
                        continue;
                    } else if ("Recall the last message".equals(msgString)) {
                        withdraw(name);
                        continue;
                    } else if (msgString.startsWith("Mass send to")) {//Send a message in the group: send it to XXX:... 1. Judge whether it is in group XXX 2 Mass content
                        int index = msgString.indexOf(':');
                        if (index == -1) {
                            index = msgString.indexOf(": ");
                        }
                        String theGroupName = msgString.substring(3, index);//Group chat name
                        String theMsg = msgString.substring(index + 1);//content
                        sendToGroup(theGroupName, isIllegal(theMsg), name);
                        continue;
                    }
                    if ("exit".equals(msgString)) {//Manually exit the program
                        remove(name);
                        sendToAll("[System notification] "" + name + ""Has been manually offline.");// Notify all clients that so and so customer has been offline
                    }
                    //Otherwise: (send messages randomly) traverse all output streams and forward the information sent by the client to all clients
                    System.out.println(name + ": " + isIllegal(msgString));
                    sendToSomeone(name, isIllegal(msgString));

                    msgList.add(msgString);
                    storeMessages.put(name, msgList);
                }
            } catch (Exception e) {
                // e.printStackTrace();
            } finally {
                remove(name);
                sendToAll("[System notification] "" + name + ""It's offline.");// Notify all clients that so and so customer has been offline
                if (socket != null) {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    private boolean isBlank(String msg) {
        return msg == null || "".equals(msg.trim());
    }

    private void putIn(String name, PrintWriter value, Map<String, PrintWriter> store) {
        synchronized (this) {
            store.put(name, value);
        }
    }

    /**
     * Removes the given output stream from the shared collection
     */
    private synchronized void remove(String key) {
        storeInfo.remove(key);
        System.out.println("The number of people currently online in the system is:" + storeInfo.size());
    }

    /**
     * Forward the given message to all clients (group sending)
     */
    private synchronized void sendToAll(String message) {
        for (PrintWriter everyone : storeInfo.values()) {
            everyone.println(message);
        }
    }

    /**
     * Mass messaging
     *
     * @param groupName Group chat name
     * @param message   Mass content
     * @param username  Message sender
     */
    private synchronized void sendToGroup(String groupName, String message, String username) {
        LinkedList<String> nickNameList = aGroup.get(groupName);
        if (nickNameList == null) {
            sendToSomeone(username, "The specified group was not found:" + groupName);
        } else {
            for (String name : nickNameList) {
                sendToSomeone(name, "["+groupName + "]Group“" + username + ""say" + message);
            }
        }
    }


    /**
     * Forward the given message to the client of private chat
     */
    private synchronized boolean sendToSomeone(String name, String message) {//Each name corresponds to a PrintWriter that only sends information to it
        PrintWriter pw = storeInfo.get(name); //Take out the chat information of the corresponding client and send it as private chat content (equivalent to sending it only to the specified name)
        if (pw != null) {
            pw.println(message);
            return true;
        }
        return false;
    }

    private static final SensitiveFilter sensitiveFilter = new SensitiveFilter();

    /**
     * Check whether the information read from the server is legal -- > the read does not contain sensitive information
     * No filter sensitive words
     */
    private synchronized String isIllegal(String message) {
        String msg = sensitiveFilter.filter(message);
        if (msg == null) {
            return "[System prompt]: The message is empty. Sending failed";
        }
        return msg;
    }


    private synchronized void creatGroup(String msgString, String hostname) {
        String groupName = msgString.substring(4);
        //1. Create a Map and add group owners and group chat names
        LinkedList<String> nickNameList = new LinkedList<>();
        nickNameList.add(hostname);
        aGroup.put(groupName, nickNameList);
        //2. Send information to the client and ask who to invite
        sendToSomeone(hostname, "Yours[" + groupName + "]Group chat created successfully! You can invite people");
        System.out.println(""" + hostname + ""New[" + groupName + "]Group chat");
        //3. The group leader sends a message to invite other members
    }

    private synchronized void groupInvite(String msgString, String hostname) {
        //"xx Group invitation: nickname"
        int locate = msgString.indexOf("Group invitation:");
        String subString = msgString.substring(locate + 4);//Get nickname
        String groupname = msgString.substring(0, locate);//Group chat name
        //3.2 who is checking 	 (find key)
        Set<String> names = storeInfo.keySet();
        for (String needName : names) {
            if (needName.equals(subString)) {
                sendToSomeone(needName, "Group leader“" + hostname + ""Invite you to join[" + groupname + "] Group chat");
                sendToSomeone(hostname, "Group invitation information sent successfully, wait“" + needName + ""respond");
                return;
            }
        }
        //No members found
        sendToSomeone(hostname, "Sorry, I didn't find it“ " + subString + ""Member, please try again.");
    }

    /**
     * For example: I want to join the group: (Group)
     *
     * @param groupName Group entry statement
     * @param aName     Sender name
     * @return true The description contains the instruction of entering or leaving the group
     */
    private synchronized void acceptGroup(String groupName, String aName) {
        //Traverse known group chat
        String hostname = null;
        LinkedList<String> nickList = aGroup.get(groupName);
        if (nickList == null) {
            sendToSomeone(aName, "Failed to join the group. The group name you entered is invalid!");
        } else {
            //Join the group and inform everyone in the group
            nickList.add(aName);
            aGroup.put(groupName, nickList);
            for (String s : nickList) {
                sendToSomeone(s, "[System message]: Just now“" + aName + ""Has joined the group[" + groupName + "]la");
            }
        }
    }


    /**
     * User withdrawal
     */
    private synchronized void exitGroup(String groupName, String aName) {
        LinkedList<String> nickNameList = aGroup.get(groupName);
        if (nickNameList == null) {
            sendToSomeone(aName, "Failed to withdraw from the group. The group name you entered is invalid!");
        } else {
            nickNameList.remove(aName);
            aGroup.put(groupName, nickNameList);
            sendToSomeone(aName, "You have successfully retired from the group["+groupName+"]Yes");
            sendToGroup(groupName, aName+"withdraw from a group!", aName);
        }
    }

    /**
     * Show group chat I joined
     */
    private synchronized List<String> showMyGroups(String aName) {
        List<String> listGroup = new ArrayList<>();
        for (String group : aGroup.keySet()) {
            LinkedList<String> nickNameList = aGroup.get(group);
            if (nickNameList.contains(aName)) {
                listGroup.add(group);
            }
        }
        return listGroup;
    }

    public synchronized void printOnlineUser(String myName) {
        Set<String> set = storeInfo.keySet();
        StringBuilder sb = new StringBuilder().append("All online users:{");
        for (String obj : set) {
            sb.append(obj).append(",");
        }
        sb.deleteCharAt(sb.length() - 1);
        sb.append("}");
        sendToSomeone(myName, sb.toString());
    }

    /**
     * Print all messages I've sent before
     */
    public synchronized void printAllMessages(String name) {
        Set<String> set = storeMessages.keySet();
        String sb = "My previous messages are:" + isIllegal(storeMessages.get(name).toString());
        sendToSomeone(name, sb);
    }

    /**
     * The withdrawal of a message depends on the demand. You can withdraw the latest message
     *
     * @param name
     */
    public synchronized void withdraw(String name) {
        LinkedList<String> list = storeMessages.get(name);
        if (list == null || list.isEmpty()){
            sendToSomeone(name, name + "There is no message to withdraw");
            return;
        }
        String removeMsg = list.remove(list.size() - 1);
        storeMessages.put(name, list);
        sendToSomeone(name, name + "Successfully recalled recent messages:" + removeMsg);
        System.out.println(name + "Just withdrawn[" + removeMsg + "]news");
    }

    public static void print() {
        System.out.println("|\t\t Prompt information\t\t\t\t\t\t|");
        System.out.println("| Private chat:@xxx:. . . (content)\t\t\t\t|");
        System.out.println("| Group chat:①New group: xxx	②Group invitation: XX Group invitation: nickname	|");
        System.out.println("| ③Agree to join the group: I want to join the group: XXX	④Retreat: Retreat: XXX	|");
        System.out.println("| Recall the last message |");
        System.out.println("| View message record  ||  Check the group chat I joined \t⑤Mass messaging: mass messaging to XXX:. . .  |");
        System.out.println("|Note: sensitive words include:" + sensitiveFilter.getSensitiveWords().toString());
        System.out.println("| For log out[exit]      |");
        System.out.println("+-----------------------------------------------+");
    }

}

TCPClient

package test1;

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class TCPClient {
    /**
     * Represents a client
     */
    static private Socket clientSocket;

    public static void main(String[] args) throws IOException {
        TCPServer.print();
        clientSocket = new Socket("localhost", 9999);
        TCPClient client = new TCPClient();
        client.start();
    }

    public void start() {
        try {
            System.out.println("Client created successfully!---Automatically logged in to this computer IP: " + clientSocket.getInetAddress().getHostAddress());
            Scanner scanner = new Scanner(System.in);
            //Set Nickname 
            setName(scanner);
            // ① The thread receiving the information sent by the server starts
            ExecutorService exec = Executors.newCachedThreadPool();
            exec.execute(new listenerServer());//Listen for messages from the server

            // ② Create an output stream and send information to the server. / / character stream = = > byte stream; Set to true to automatically refresh the buffer
            PrintWriter pw = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(), StandardCharsets.UTF_8), true);

            while (true) {
                String msg = scanner.nextLine();
                if ("".equals(msg.trim())) {
                    System.out.println("[System prompt]: The message sent by yourself cannot be empty");
                    continue;
                }
                //Print what you say
                pw.println(msg);
                if (msg.equals("exit")) {
                    System.out.println("You have exited the client program");
                    clientSocket.shutdownOutput();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {//Close Socket
            if (clientSocket != null) {
                try {
                    System.out.println("You are offline");
                    clientSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * Set nickname and log in
     */
    private void setName(Scanner scan) throws Exception {
        String name;
        //Create output stream
        PrintWriter pw = new PrintWriter(
                new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8"), true);
        //Create input stream
        BufferedReader br = new BufferedReader(
                new InputStreamReader(clientSocket.getInputStream(), "UTF-8"));
        while (true) {
            System.out.println("Please create your nickname (login):");
            name = scan.nextLine();
            if ("".equals(name.trim())) {
                System.out.println("Nickname cannot be empty");
            } else {
                pw.println(name);
                String pass = br.readLine();
                if (pass != null && (!"OK".equals(pass))) {     /*Receive the information obtained from the input sent by br       */
                    System.out.println("The nickname has been occupied, please re-enter:");
                } else {
                    System.out.println("Nickname“" + name + ""It has been set up successfully. You can start chatting");
                    break;
                }
            }
        }

    }

    /**
     * Monitoring (when the customer is doing other things, this is also running all the time, so it can receive the information from the server)
     * Cycle to read the information sent by the server and output it to the console of the client
     * Receive information, print one sentence at a time
     */
    class listenerServer implements Runnable {
        @Override
        public void run() {
            try {
                BufferedReader br = new BufferedReader(//Read the input stream of clientSocket and print it
                        new InputStreamReader(clientSocket.getInputStream(), StandardCharsets.UTF_8));
                String msgString;
                while ((msgString = br.readLine()) != null) {
                    System.out.println(msgString);
                }
            } catch (Exception e) {
                System.out.println("An exception occurred");
                e.printStackTrace();
            }
        }
    }

}

SensitiveFilter

Realize the function of filtering sensitive words:

Note the contents of the read file here:

getResource method: find the resource with the given name. The rules for searching resources associated with a given class are implemented by the class definition class loader. This method delegates to the class loader of this object. If this object is loaded by the bootstrap class loader, the method is delegated to classloader getSystemResource .

String filePath = SensitiveFilter.class.getResource("sensitive-words.txt").getPath();

At this time, the printed filePath is the absolute path of the file. Then use the Reader to read:

BufferedReader reader = new BufferedReader(new FileReader(filePath));

package test1;

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class TCPClient {
    /**
     * Represents a client
     */
    static private Socket clientSocket;

    public static void main(String[] args) throws IOException {
        TCPServer.print();
        clientSocket = new Socket("localhost", 9999);
        TCPClient client = new TCPClient();
        client.start();
    }

    public void start() {
        try {
            System.out.println("Client created successfully!---Automatically logged in to this computer IP: " + clientSocket.getInetAddress().getHostAddress());
            Scanner scanner = new Scanner(System.in);
            //Set Nickname 
            setName(scanner);
            // ① The thread receiving the information sent by the server starts
            ExecutorService exec = Executors.newCachedThreadPool();
            exec.execute(new listenerServer());//Listen for messages from the server

            // ② Create an output stream and send information to the server. / / character stream = = > byte stream; Set to true to automatically refresh the buffer
            PrintWriter pw = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(), StandardCharsets.UTF_8), true);

            while (true) {
                String msg = scanner.nextLine();
                if ("".equals(msg.trim())) {
                    System.out.println("[System prompt]: The message sent by yourself cannot be empty");
                    continue;
                }
                //Print what you say
                pw.println(msg);
                if (msg.equals("exit")) {
                    System.out.println("You have exited the client program");
                    clientSocket.shutdownOutput();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {//Close Socket
            if (clientSocket != null) {
                try {
                    System.out.println("You are offline");
                    clientSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * Set nickname and log in
     */
    private void setName(Scanner scan) throws Exception {
        String name;
        //Create output stream
        PrintWriter pw = new PrintWriter(
                new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8"), true);
        //Create input stream
        BufferedReader br = new BufferedReader(
                new InputStreamReader(clientSocket.getInputStream(), "UTF-8"));
        while (true) {
            System.out.println("Please create your nickname (login):");
            name = scan.nextLine();
            if ("".equals(name.trim())) {
                System.out.println("Nickname cannot be empty");
            } else {
                pw.println(name);
                String pass = br.readLine();
                if (pass != null && (!"OK".equals(pass))) {     /*Receive the information obtained from the input sent by br       */
                    System.out.println("The nickname has been occupied, please re-enter:");
                } else {
                    System.out.println("Nickname“" + name + ""It has been set up successfully. You can start chatting");
                    break;
                }
            }
        }

    }

    /**
     * Monitoring (when the customer is doing other things, this is also running all the time, so it can receive the information from the server)
     * Cycle to read the information sent by the server and output it to the console of the client
     * Receive information, print one sentence at a time
     */
    class listenerServer implements Runnable {
        @Override
        public void run() {
            try {
                BufferedReader br = new BufferedReader(//Read the input stream of clientSocket and print it
                        new InputStreamReader(clientSocket.getInputStream(), StandardCharsets.UTF_8));
                String msgString;
                while ((msgString = br.readLine()) != null) {
                    System.out.println(msgString);
                }
            } catch (Exception e) {
                System.out.println("An exception occurred");
                e.printStackTrace();
            }
        }
    }

}

sensitive-words.txt

This is the sensitive vocabulary stored.
For example, my: note that the SensitiveFilter class will read sensitive words line by line!

Topics: Java socket