Java Socket + Multithreading to Realize Multi person Chat Room Function

  • 2021-11-01 03:06:33
  • OfStack

This article example for everyone to share Java Socket + multi-threaded implementation of multi-person chat room specific code, for your reference, the specific content is as follows

Brief introduction of ideas

It is divided into two classes: client and server. All the clients send the chat content to the server. After the server accepts it, it sends every one content to every one client, and the client displays it on the terminal.

Client design

Client contains two threads, one for receiving server information, then display, one for receiving keyboard input, sent to the server.


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
 
public class WeChatClient {  //WeChat Client class of 
    private Socket client;
    private String name;
    private InputStream in;
    private OutputStream out;
    private MassageSenter massageSenter;
    private MassageGeter massageGeter;
    class MassageGeter extends Thread{  //1 Child thread class for clients to receive messages 
        MassageGeter() throws IOException{
            in = client.getInputStream();
        }
        @Override
        public void run() {
            int len;
            byte[] bytes = new byte[1024];
            try {
                while ((len = in.read(bytes)) != -1) { // This function is blocked 
                    System.out.println(new String(bytes,0,len, StandardCharsets.UTF_8));
                }
            }catch (IOException e){
                System.out.println(e.toString());
            }
            System.out.println("Connection interruption");
        }
    }
    class MassageSenter extends Thread{  //1 Child thread class, which is used to send messages to the server 
        MassageSenter() throws IOException{
            out = client.getOutputStream();
        }
 
        @Override
        public void run() {
            Scanner scanner = new Scanner(System.in);
            try {
                while (scanner.hasNextLine()) { // This function is a blocked function 
                    String massage = scanner.nextLine();
                    out.write((name + " : " + massage).getBytes(StandardCharsets.UTF_8));
                    if(massage.equals("//exit"))
                        break;
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
 
    WeChatClient(String name, String host, int port) throws IOException {// Initialize, instantiate send and receive 2 Threads 
        this.name = name;
        client = new Socket(host,port);
        massageGeter = new MassageGeter();
        massageSenter = new MassageSenter();
 
    }
 
    void login() throws IOException{// When logging in, send the name to the server first, and start the thread after receiving the correct response from the server 
        out.write(name.getBytes(StandardCharsets.UTF_8));
        byte[] bytes = new byte[1024];
        int len;
        len = in.read(bytes);
        String answer = new String(bytes,0,len, StandardCharsets.UTF_8);
        if(answer.equals("logined!")) {
            System.out.println("Welcome to WeChat! "+name);
            massageSenter.start();
            massageGeter.start();
            try {
                massageSenter.join();//join() The function of is to wait for the thread to finish before continuing to execute the main thread (main)
                massageGeter.join();
            }catch (InterruptedException e){
                System.err.println(e.toString());
            }
 
        }else{
            System.out.println("Server Wrong");
        }
        client.close();
    }
 
 
    public static void main(String[] args) throws IOException{// Program entry 
        String host = "127.0.0.1";
        WeChatClient client = new WeChatClient("Uzi",host,7777);
        client.login();
    }
 
}

Server design

The server consists of three thread classes: port listening thread, client receiving information thread and sending information thread.

The server class also contains and maintains a list of connected users and a list of messages to be sent.

The server has a thread responsible for listening to the port, which adds the connected client to the user list after receiving the connection request from the client; And instantiate one thread class for each connected client to receive information from each client and store it in the list of information to be sent.

The thread of sending information checks whether the list is empty, and if it is not empty, it sends the information inside to every 1 user in the user list.


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
 
public class WeChatServer {
    private ServerSocket server;
    private ArrayList<User> users;// User list 
    private ArrayList<String> massages;// Message queue to be sent 
    private Listener listener;
    private MassageSenter massageSenter;
 
 
    class User{  // User class, which contains the login of the user id And 1 Output streams 
        String name;
        OutputStream out;
        User(String name,OutputStream out){
            this.name = name;
            this.out = out;
        }
 
        @Override
        public String toString() {
            return name;
        }
    }
 
    private static String GetMassage(InputStream in) throws IOException{// From 1 Input stream reception 1 String 
        int len;
        byte[] bytes = new byte[1024];
        len = in.read(bytes);
        return new String(bytes,0,len,StandardCharsets.UTF_8);
    }
    private void UserList(){  // List the current online users for debugging 
        for(User user : users)
            System.out.println(user);
    }
 
    class Listener extends Thread{ // Listen to the thread class, and if it is negative, listen to whether there is a client connection 
        @Override
        public void run() {
            try {
                while (true) {
                    Socket socket = server.accept();// This function is blocked 
                    InputStream in = socket.getInputStream();
                    String name = GetMassage(in);// Object of the access user name
                    System.out.println(name +" has connected");
                    massages.add(name+" has joined just now!!");// Report the information connected by the user to the chat room 
                    OutputStream out = socket.getOutputStream();
                    out.write("logined!".getBytes(StandardCharsets.UTF_8));// Send feedback that the connection was successfully established 
                    User user = new User(name,out);
                    users.add(user);// Add to Online Users List 
                    MassageListener listener = new MassageListener(user,in);// Create a thread to receive this user information 
                    listener.start();
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
    class MassageListener extends Thread{ // The receiving thread class is used from the 1 Clients receive information and add it to the list to be sent 
        private User user;
        private InputStream in;
        MassageListener(User user,InputStream in){
            this.user = user;
            this.in = in;
        }
 
        @Override
        public void run() {
            try {
                while (true){
                    String massage = GetMassage(in);
                    System.out.println("GET MASSAGE  "+massage);
                    if(massage.contains("//exit")){ //       "/exit"  Is an exit command 
                        break;
                    }
                    massages.add(massage);
                }// There are two forms of user exit, and enter   " //exit "   Or close the program directly 
                in.close();
                user.out.close();
 
            }catch (IOException e){// This exception is to handle the abnormal shutdown of the client, that is GetMassage(in) Call throws an exception because in The incoming and outgoing flow has been automatically closed 
                e.printStackTrace();
            }finally {
                System.out.println(user.name+" has exited!!");
                massages.add(user.name+" has exited!!");
                users.remove(user);// You must remove the disconnected user from the user list, or an exception will be generated when sending information 
                System.out.println("Now the users has");
                UserList();
            }
 
        }
    }
    private synchronized void SentToAll(String massage)throws IOException{// Send information to every 1 Users, join synchronized Decoration to ensure that the user list will not be changed by other threads when sending 
        if(users.isEmpty())
            return;
        for(User user : users){
            user.out.write(massage.getBytes(StandardCharsets.UTF_8));
        }
    }
 
    class MassageSenter extends Thread{// Message sending thread 
 
        @Override
        public void run() {
            while(true){
                try{
                    sleep(1);// There are no blocked functions in this thread, and sleep statements are added to prevent the thread from preempting resources too much 
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
                if(!massages.isEmpty()){
                    String massage = massages.get(0);
                    massages.remove(0);
                    try {
                        SentToAll(massage);
                    }catch (IOException e){
                        e.printStackTrace();
                    }
 
                }
            }
        }
    }
 
    WeChatServer(int port) throws IOException {  // Initialization 
        server = new ServerSocket(port);
        users = new ArrayList<>();
        massages = new ArrayList<>();
        listener = new Listener();
        massageSenter = new MassageSenter();
    }
 
    private void start(){ // Thread startup 
        listener.start();
        massageSenter.start();
    }
 
    public static void main(String[] args) throws IOException{
        WeChatServer server = new WeChatServer(7777);
        server.start();
    }
 
}

Summarize

Multithreaded programming is required because some functions are blocked, such as


while ((len = in.read(bytes)) != -1) { // This function is blocked 
    System.out.println(new String(bytes,0,len, StandardCharsets.UTF_8));
}

while (scanner.hasNextLine()) { // This function is a blocked function 
        String massage = scanner.nextLine();
        out.write((name + " : " + massage).getBytes(StandardCharsets.UTF_8));
        if(massage.equals("//exit"))
     break;
  }

Socket socket = server.accept();// This function is blocked 

These blocked functions need to wait for other programs. For example, scanner. hasNextLine () needs to wait for the programmer's input before returning values. in. read needs to wait for the other side of the stream to transmit data. Using multithreading can run other threads when these functions are blocked.

Therefore, the key to multithreaded programming is those blocking functions.


Related articles: