Implementation of multi person chat room

Posted by blackandwhite on Tue, 04 Jan 2022 22:08:05 +0100

Multiplayer chat room

1, Function introduction

When each client connects to the server, it starts to send messages to the server. When receiving the client's connection, the server first outputs who entered the chat room, and then forwards the messages sent by the client to other clients to realize the function of group chat, Finally, the multi-functional (fast, real-time, multi-person) multi-person chat is realized to bring users a better experience.

2, Design conception

  • Design the interface of client and server

  1. Input box and output box
  2. User nickname
  3. Message time
  4. Add scroll bar
  5. Add button
  6. Setting of function keys
  7. Display of user access
  • Interaction between server and client

  1. First, the server should instantiate a ServerSocket object and wait for the client to connect with the accept() method.
    It is worth noting here that the accept() method in the ServreSocket class is a blocking method, that is, the accept() method will always wait in a blocking manner before obtaining the connection of the client, and will not let the following code execute until the connection of the client is obtained.

  2. While the server is waiting, we need to establish a client and apply for a connection to the server. Then, in the client code, we need to instantiate a Socket object, which should have the same port number as the server ServreSocket, so as to ensure accurate connection to the server. After successfully instantiating and creating the Socket object, it is equivalent to successfully establishing a connection with the server (provided that the requested server object has been created and is waiting for the accept() method).

  3. After the client successfully applies for a connection, we return to the accept() method on the server. After the accept() method successfully obtains the connection application, the returned value is a Socket object, which is the connection to the client.
  4. After the TCP connection between the client and the server is successfully established through the Socket object and ServerSocket object, we will start the information exchange between the server and the client through the implementation of IO flow: the input flow and output flow in the corresponding direction can be obtained through the getInputStream() method and getoutputstream() method in the Socket class.

  5. The server can write information to the client through the OutputStream stream created by using getoutputstream() method on the Socket object obtained by accept(). Similarly, the InputStream stream obtained by using getInputStream() method on the Socket object can read information from the client. And vice versa.
  • Optimize interface

  1. Solve subsequent bugs
  2. Make the user interface simpler and less cumbersome

3, Experimental results show

  • Server port

  • Client port

  • Message interaction

4, Specific code and steps

  • Interface design

1. Client

    public void init(){
        
        this.setTitle("Client window");
        this.add(sp,BorderLayout.CENTER);
        this.add(tf,BorderLayout.SOUTH);
        this.setBounds(300,300,300,400);        //Set listening for input box
        tf.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String strSend = tf.getText();   //Gets the text in the input box
                if(strSend.trim().length()==0){  //If the input box is empty, no operation will be performed(inspect)
                    return;
                }
                //strSend Method of sending server
                send(strSend);   // Send the text content to the sending server method
                tf.setText("");  // The text disappears in the text box after entering
            } 
        });
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  //Close windows and programs
        ta.setEditable(false); //You cannot type in the display box
        tf.requestFocus();     //Cursor focus
        try {
            s= new Socket(CONNSTR,CONNPORT);
            //Indicates that you are connected to the server
            isConn = true;
            
        } catch (UnknownHostException e1) {
            // TODO Automatically generated catch block
            e1.printStackTrace();
        } catch (IOException e1) {
            // TODO Automatically generated catch block
            e1.printStackTrace();
        }
        this.setVisible(true);  //Display the constructed data model
        
        new Thread(new Receive()).start();//Start multithreading

2. Server side

public ServerChat(){
        this.setTitle("Server side");
        this.add(sp,BorderLayout.CENTER); 
        btnTool.add(startBtn);
        btnTool.add(stopBtn);
        this.add(btnTool,BorderLayout.SOUTH); 
        this.setBounds(0,0,500,500);
        if(isStart){  //Determine whether the server is started
            serverta.append("Server started\n");
        }else{
            
            serverta.append("The server has not started yet. Please click the button to start it\n");
            
        }
        
        //Assign listening to the window close key
        
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                isStart = false ;
                try {
                    
                    if (ss!=null){
                        ss.close();  
                    }
                    System.out.println("Server stopped!"); 
                    serverta.append("Server Disconnected");
                    System.exit(0);  //The same is true for the close button below the exit program
                } catch (IOException e1) {
                    // TODO Automatically generated catch block
                    e1.printStackTrace();
                }
            }
        });
        //Press newplus monitor to turn it off
        stopBtn.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                
                try {
                    
                    if (ss!=null){
                        ss.close();   //Close the server connection port
                        isStart = false;
                    }
                    System.exit(0);
                    serverta.append("Server Disconnected");
                    System.out.println("Server stop!"); 
                } catch (IOException e1) {
                    // TODO Automatically generated catch block
                    e1.printStackTrace();
                }
            }
        });
        //Set a monitor for the start button
        startBtn.addActionListener(new ActionListener() { 
            
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Successfully started");
                try {
                    
                    if(ss == null){
                        ss= new ServerSocket(PORT);  //Create a server port number
                        
                    }
                    isStart = true;  //The start condition becomes true
                    serverta.append("The server has started!"+"\n"); 
                        
                } catch (IOException e1) {
                    // TODO Automatically generated catch block
                    e1.printStackTrace();
                }
                
            }
        });
        
    
        
        this.setVisible(true);  //Display the constructed data model
        startServer(); 
        
    }

 

  • Interaction between client and server port

1. Establish a channel between the client and the server

dos = new DataOutputStream(s.getOutputStream()); //Establish a send pipeline

 

2. Create a port number for the client on the server

try{
            try{
                ss = new ServerSocket(PORT);  //Create port number
                isStart=true;
            }catch (IOException e2){
                e2.printStackTrace();
            }
            //Can receive connections from multiple clients
            while(isStart){                     //Here, whether to start is used as the loop judgment condition
                Socket s =ss.accept();          //Wait here to receive the information of the client. Connect a client to a server interface
                ccList.add(new ClientConn(s));  //Each one adds information to the collection
                System.out.println("A client connects to the server:"+s.getInetAddress()+"/"+s.getPort());
                serverta.append("A client connects to the server:"+s.getInetAddress()+"/"+s.getPort()+"\n");
            }

 

3. The client sends a message

    public void send(String str){  //Get text to send
        try {
            dos = new DataOutputStream(s.getOutputStream()); //Establish a send pipeline
            dos.writeUTF(str);
        } catch (IOException e) {
            // TODO Automatically generated catch block
            e.printStackTrace();
        }
    }

 

4. The server receives messages

public void run() {
            
            try {
                DataInputStream dis =new DataInputStream(s.getInputStream());
                //In order to enable the server to receive multiple sentences from each client
                while(isStart){  //Here, whether to start is used as the loop judgment condition
                    String str =dis.readUTF(); //Receive text
                    System.out.println(s.getLocalAddress()+"|"+s.getPort()+"say:"+str+"\n");//Display on console
                    serverta.append(s.getLocalAddress()+"|"+s.getPort()+"say:"+str+"\n");   //Displayed on the server side
                    String strSend = s.getLocalAddress()+"|"+s.getPort()+"say:"+str+"\n";
                    //ergodic ccList call send Method receives information on the client, which is received by multiple threads(Multithreaded send message)                    
                    java.util.Iterator<ClientConn> it = ccList.iterator();
                    while(it.hasNext()){
                        ClientConn o = it.next();
                        o.send(strSend);      
                    }
                    
                }
                
            } catch (SocketException e){
                System.out.println("A client is offline\n");
                serverta.append(s.getLocalAddress()+"|"+s.getPort()+"The client is offline\n");  //Establish pipeline for sending
                
            }catch (IOException e) {
                // TODO Automatically generated catch block
                e.printStackTrace();
            }            
        }

 

5. The server sends a message

        public void send(String str){
            try {
                DataOutputStream dos = new DataOutputStream(this.s.getOutputStream());
                dos.writeUTF(str);
                
                
            } catch (IOException e) {
                // TODO Automatically generated catch block
                e.printStackTrace();
            }
        }

 

6. The client receives messages

    class Receive implements Runnable{ 
        @Override
        public void run() {
            try {
                while(isConn){
                    DataInputStream dis = new DataInputStream(s.getInputStream());
                    String str  = dis.readUTF();
                    ta.append(str);
                    
                    
                }
            }  catch (SocketException e) {
                
                System.out.println("Server terminated unexpectedly!");
                
                ta.append("Server terminated unexpectedly!\n");
            }catch (IOException e) {
                // TODO Automatically generated catch block
                e.printStackTrace();
            }           
        }
    }

 

7. Traverse the message sent by the client (to prevent the message from being sent back to itself)

java.util.Iterator<ClientConn> it = ccList.iterator();
                    while(it.hasNext()){
                        ClientConn o = it.next();
                        o.send(strSend);      
                    }

5, Summary

  • After consulting the blogger blog and related documents to complete the multi person chat room project, although our code ability is not very obvious, but after this campaign, my java skills deepened, and the design and thinking of the project have a certain breadth and depth.
  • After completing the multi person chat project, the biggest help to me is to let me understand the concept of an intermediate level Socket
  • We always thought that after the client sends a message, the server must process it immediately, but in fact, some intermediate forwarding processes can be set, such as message queue to save the data in the sending process. This can improve the response rate and stability of the system, so as to avoid some uncertain factors, such as decoupling and during message peak, If the step frequencies of the sender and the receiver are inconsistent, intermediate forwarding can make up for the inconsistency between the step frequencies of producers and consumers

  • In the process of writing server code, there are pits everywhere, and the reported errors should be handled one by one to achieve better optimization

 

 

Team members:

Liu Longjun, Guo Runfang, Hui Wenkai, Xing Runhu

 

Link: https://pan.baidu.com/s/1kP3PY71-Ev-e_ulc7MNomg
Extraction code: 4ezx