Java multithreading realizes multi-user and server-side Socket communication

table of Contents

Foreword review

1. Multi-user server

Second, use thread pool to achieve server-side multithreading

1. Single-threaded version

2. Multi-threaded version

3. Multi-user and server communication demonstration

Fourth, the complete code of the multi-user server

At last


Foreword review

In the previous article " Java Multithreading to Realize TCP Network Socket Programming (C/S Communication) ", we solved the problem that the server side continuously sends multiple messages to the client to receive after the connection is established. The solution is easy to understand, and the customer The function of receiving information at the end is concentrated to the thread for processing, realizing multi-thread synchronization.

In the same way, the last concluding remark leaves a question. In short, it is equivalent to multiple users accessing server resources. The server should establish a connection with each client and conduct communication dialogues , just like our daily use of QQ, WeChat, video, etc. The client is an example of multi-user communication with the server.

In the previous article, the server only realized the function of a single user. This article will solve this problem and record the realization of multithreading on the server in detail. The goal is that multiple users (clients) can establish connections and communicate with the server at the same time to avoid blocking , To further improve TCP Socket network communication, use Java multi-threading technology to achieve multi-user and server Socket communication!

Java implementation of socket communication network programming series of articles:

  1. Network Socket programming based on UDP protocol (C/S communication case in java) [ https://blog.csdn.net/Charzous/article/details/109016215 ]
  2. Network socket programming based on TCP protocol (java realizes C/S communication) [ https://blog.csdn.net/Charzous/article/details/109016215 ]
  3. Java multithreading to realize TCP network Socket programming (C/S communication) [ https://blog.csdn.net/Charzous/article/details/109283697 ]

1. Multi-user server

Multi-user server means that the server can support multiple users to concurrently access the service resources provided by the server, such as chat service, file transfer, etc.

The TCPServer in the previous article is a single-user version and can only talk to one user at a time. We can try to connect with multiple users and open multiple clients. The specific operations are as follows:

This allows multiple clients to be executed in parallel at the same time. The test found that the single-user version of the TCPServer.java program can support concurrent connections of multiple users at the same time (TCP three-way handshake), but cannot serve multi-user conversations at the same time, only after the previous user exits , The subsequent users can complete the server connection.

Multithreading technology, parallel execution of thread calls.

The last article mentioned that there are two ways to implement multithreading in Java, one is to use the Thread class, and the other is to use the Runnable class and implement the run() method . The following will use the Runnable class to encapsulate the related operation functions of the server. In combination with the previous article, you will learn two multithreading implementation methods.

//使用Runnable类,作为匿名内部类
class Handler implements Runnable {
    public void run() {
   //实现run方法
    }
}

The server faces many concurrent connections from clients. The multi-threaded solution in this case is generally:

  1. The main thread is only responsible for listening to client requests and accepting connection requests, and a thread is dedicated to talking to a customer , that is , after a customer request is successful, a new thread is created to take care of the customer. For this scheme, you can use the new Thread method in the previous article to create threads, but frequent thread creation requires a lot of system resources. So this method is not used.
  2. For servers, thread pools are generally used to manage and reuse threads . Several threads are maintained inside the thread pool. When there are no tasks, these threads are all in a waiting state. If there is a new task, an idle thread is allocated for execution. If all threads are busy, new tasks are either placed in the queue and waiting, or a new thread is added for processing.

Obviously, we use the second thread pool method. Common creation methods are as follows:

ExecutorService executorService = Executors.newFixedThreadPool(n);//指定线程数量
ExecutorService executorService = Executors.newCachedThreadPool();//动态线程池

The next step is to select the type of thread pool. Using the first thread pool with a fixed number of threads is obviously not flexible enough. The second thread pool will dynamically adjust the size of the thread pool according to the number of tasks. As a small concurrent use, it is not a big problem, but it is not used in the actual production environment. Appropriate, if the amount of concurrency is too large, it will often cause OutOfMemoryError. According to our application scenarios, we can use this to dynamically adjust the thread pool.

Second, use thread pool to achieve server-side multithreading

1. Single-threaded version

First of all, compared with the previous single-threaded communication, the following code can only realize the communication between a single user and the server. If multiple users communicate with the server, it will be blocked.

    //单客户版本,每次只能与一个用户建立通信连接
    public void Service(){
        while (true){
            Socket socket=null;
            try {
                //此处程序阻塞,监听并等待用户发起连接,有连接请求就生成一个套接字
                socket=serverSocket.accept();

                //本地服务器控制台显示客户连接的用户信息
                System.out.println("New connection accepted:"+socket.getInetAddress());
                BufferedReader br=getReader(socket);//字符串输入流
                PrintWriter pw=getWriter(socket);//字符串输出流
                pw.println("来自服务器消息:欢迎使用本服务!");

                String msg=null;
                //此处程序阻塞,每次从输入流中读入一行字符串
                while ((msg=br.readLine())!=null){
                    //如果用户发送信息为”bye“,就结束通信
                    if(msg.equals("bye")){
                        pw.println("来自服务器消息:服务器断开连接,结束服务!");
                        System.out.println("客户端离开。");
                        break;
                    }
                    msg=msg.replace("?","!").replace("?","!")
                            .replace("吗","").replace("吗?","").replace("在","没");
                    pw.println("来自服务器消息:"+msg);
                    pw.println("来自服务器,重复消息:"+msg);
                }
            }catch (IOException e){
                e.printStackTrace();
            }finally {
                try {
                    if (socket!=null)
                        socket.close();//关闭socket连接以及相关的输入输出流
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }

 Therefore, based on the above analysis, the single-threaded version of the server-client communication and dialogue functions are handled independently and handled by one thread. This will not block the execution of the main process. The specific implementation is as follows.

 2. Multi-threaded version

 

1. Create an anonymous inner class Handler, implement the run method of the Runnable class, and put the communication dialogue in run():

    class Handler implements Runnable {
        private Socket socket;

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

        public void run() {
            //本地服务器控制台显示客户端连接的用户信息
            System.out.println("New connection accept:" + socket.getInetAddress());
            try {
                BufferedReader br = getReader(socket);
                PrintWriter pw = getWriter(socket);

                pw.println("From 服务器:欢迎使用服务!");

                String msg = null;
                while ((msg = br.readLine()) != null) {
                    if (msg.trim().equalsIgnoreCase("bye")) {
                        pw.println("From 服务器:服务器已断开连接,结束服务!");

                        System.out.println("客户端离开。");
                        break;
                    }
                    pw.println("From 服务器:" + msg);
                    pw.println("来自服务器,重复消息:"+msg);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (socket != null)
                        socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

 2. Use newCachedThreadPool() to dynamically create a thread pool

Thread pool as a member variable:

    //创建动态线程池,适合小并发量,容易出现OutOfMemoryError
    private ExecutorService executorService=Executors.newCachedThreadPool();

 Create a new thread in the Service method of the server and hand it over to the thread pool for processing.

 

    //多客户版本,可以同时与多用户建立通信连接
    public void Service() throws IOException {
        while (true){
            Socket socket=null;
                socket=serverSocket.accept();
                //将服务器和客户端的通信交给线程池处理
                Handler handler=new Handler(socket);
                executorService.execute(handler);
            }
    }

3. Multi-user and server communication demonstration

When the server previously only supported single-user communication sessions, the information sent by the new user was blocked and the server could not return.

It is interesting to find that the other end ends the communication, and at the same time, the other end immediately receives the reply message from the server.

From the preliminary observation of the displayed time, it can be judged that the previously sent information is blocked in the server process. After the connection of one party is disconnected, the server sends the blocked queue information to the client. What is the result after using multithreading?

Further experience in moving picture demonstration:

 

Fourth, the complete code of the multi-user server

/*
 * TCPThreadServer.java
 * Copyright (c) 2020-11-02
 * author : Charzous
 * All right reserved.
 */

package chapter05;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TCPThreadServer {
    private int port =8008;//服务器监听窗口
    private ServerSocket serverSocket;//定义服务器套接字
    //创建动态线程池,适合小并发量,容易出现OutOfMemoryError
    private ExecutorService executorService=Executors.newCachedThreadPool();

    public TCPThreadServer() throws IOException{
        serverSocket =new ServerSocket(8008);
        System.out.println("服务器启动监听在"+port+"端口...");

    }

    private PrintWriter getWriter(Socket socket) throws IOException{
        //获得输出流缓冲区的地址
        OutputStream socketOut=socket.getOutputStream();
        //网络流写出需要使用flush,这里在printWriter构造方法直接设置为自动flush
        return new PrintWriter(new OutputStreamWriter(socketOut,"utf-8"),true);
    }

    private BufferedReader getReader(Socket socket) throws IOException{
        //获得输入流缓冲区的地址
        InputStream socketIn=socket.getInputStream();
        return new BufferedReader(new InputStreamReader(socketIn,"utf-8"));
    }

    //多客户版本,可以同时与多用户建立通信连接
    public void Service() throws IOException {
        while (true){
            Socket socket=null;
                socket=serverSocket.accept();
                //将服务器和客户端的通信交给线程池处理
                Handler handler=new Handler(socket);
                executorService.execute(handler);
            }
    }


    class Handler implements Runnable {
        private Socket socket;

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

        public void run() {
            //本地服务器控制台显示客户端连接的用户信息
            System.out.println("New connection accept:" + socket.getInetAddress());
            try {
                BufferedReader br = getReader(socket);
                PrintWriter pw = getWriter(socket);

                pw.println("From 服务器:欢迎使用服务!");

                String msg = null;
                while ((msg = br.readLine()) != null) {
                    if (msg.trim().equalsIgnoreCase("bye")) {
                        pw.println("From 服务器:服务器已断开连接,结束服务!");

                        System.out.println("客户端离开。");
                        break;
                    }

                    pw.println("From 服务器:" + msg);
                    pw.println("来自服务器,重复消息:"+msg);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (socket != null)
                        socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) throws IOException{
        new TCPThreadServer().Service();
    }

}


At last

This article will solve the problem of server-side multi-user communication, and record the realization of server-side multi-threading in detail. The goal is that multiple users (clients) can establish connections and communicate with the server at the same time, avoid blocking, and further improve TCP Socket network communication. Use Java multithreading technology to realize multi-user and server-side Socket communication! In short, it is equivalent to multiple users accessing server resources. The server should establish a connection with each client. Just like our daily use of QQ, WeChat, and video clients, it is an example of multi-user communication with the server.

Old question, ๑乛◡乛๑, it seems that after finishing this, what interesting can be achieved? Stay here and think for 3 seconds!

……

……

……

That is: to achieve a group chat room, similar to QQ, WeChat group chat, you can communicate between multiple users, does it feel very interesting?

Based on this article's multi-threading technology to achieve multi-user server-side functions, can it solve the group chat room function? To achieve this function, wait for the next update!

If you think it’s good, welcome to "one-click, three-link", like, bookmark, follow, comment directly if you have any questions, and exchange and learn!

Java implementation of socket communication network programming series of articles:

  1. Network Socket programming based on UDP protocol (C/S communication case in java) [ https://blog.csdn.net/Charzous/article/details/109016215 ]
  2. Network socket programming based on TCP protocol (java realizes C/S communication) [ https://blog.csdn.net/Charzous/article/details/109016215 ]
  3. Java multithreading to realize TCP network Socket programming (C/S communication) [ https://blog.csdn.net/Charzous/article/details/109283697 ]

My CSDN blog: https://blog.csdn.net/Charzous/article/details/109440277

Guess you like

Origin blog.csdn.net/Charzous/article/details/109440277