Java Multithreading realisiert die Socket-Kommunikation für mehrere Benutzer und Server

Inhaltsverzeichnis

Vorwort Bewertung

1. Mehrbenutzerserver

Verwenden Sie zweitens den Thread-Pool, um serverseitiges Multithreading zu erreichen

1. Single-Threaded-Version

2. Multithread-Version

3. Demonstration der Kommunikation zwischen mehreren Benutzern und Servern

Viertens der vollständige Code des Mehrbenutzerservers

Zu guter Letzt


Vorwort Bewertung

Im vorherigen Artikel " Java-Multithreading zur Realisierung der TCP-Netzwerksocket-Programmierung (C / S-Kommunikation) " haben wir das Problem gelöst, dass die Serverseite kontinuierlich mehrere Nachrichten an den Client sendet, um sie nach dem Herstellen der Verbindung zu empfangen. Die Lösung ist leicht zu verstehen und der Kunde Die Funktion zum Empfangen von Informationen am Ende wird zur Verarbeitung auf den Thread konzentriert, wodurch eine Multithread-Synchronisation realisiert wird.

Auf die gleiche Weise hinterlässt die letzte abschließende Bemerkung eine Frage: Kurz gesagt, sie entspricht dem Zugriff mehrerer Benutzer auf Serverressourcen. Der Server sollte eine Verbindung zu jedem Client herstellen und Kommunikationsdialoge führen , genau wie unsere tägliche Verwendung von QQ, WeChat, Video usw. Der Client ist ein Beispiel für die Mehrbenutzerkommunikation mit dem Server.

Im vorherigen Artikel hat der Server nur die Funktion eines einzelnen Benutzers erkannt. In diesem Artikel wird dieses Problem gelöst und die Realisierung von Multithreading auf dem Server detailliert aufgezeichnet. Ziel ist, dass mehrere Benutzer (Clients) gleichzeitig Verbindungen herstellen und mit dem Server kommunizieren können, um ein Blockieren zu vermeiden , Um die TCP-Socket-Netzwerkkommunikation weiter zu verbessern, verwenden Sie die Java-Multithreading-Technologie, um eine Socket-Kommunikation für mehrere Benutzer und Server zu erreichen!

Java-Implementierung der Programmierreihe zur Programmierung von Socket-Kommunikationsnetzen:

  1. Network Socket-Programmierung basierend auf dem UDP-Protokoll (C / S-Kommunikationsfall in Java) [ https://blog.csdn.net/Charzous/article/details/109016215 ]
  2. Netzwerk-Socket-Programmierung basierend auf dem TCP-Protokoll (Java realisiert die C / S-Kommunikation) [ https://blog.csdn.net/Charzous/article/details/109016215 ]
  3. Java-Multithreading zur Realisierung der TCP-Netzwerk-Socket-Programmierung (C / S-Kommunikation) [ https://blog.csdn.net/Charzous/article/details/109283697 ]

1. Mehrbenutzerserver

Mehrbenutzerserver bedeutet, dass der Server mehrere Benutzer unterstützen kann, um gleichzeitig auf die vom Server bereitgestellten Serviceressourcen wie Chat-Service, Dateiübertragung usw. zuzugreifen.

Der TCPServer im vorherigen Artikel ist eine Einzelbenutzerversion und kann jeweils nur mit einem Benutzer kommunizieren. Wir können versuchen, eine Verbindung mit mehreren Benutzern herzustellen und mehrere Clients zu öffnen. Die spezifischen Vorgänge sind wie folgt:

Auf diese Weise können mehrere Clients gleichzeitig ausgeführt werden. Der Test ergab, dass die Einzelbenutzerversion des Programms TCPServer.java gleichzeitige Verbindungen mehrerer Benutzer gleichzeitig unterstützen kann (TCP-Drei-Wege-Handshake), jedoch keine Mehrbenutzer-Konversationen gleichzeitig bedienen kann, nachdem der vorherige Benutzer beendet wurde Die nachfolgenden Benutzer können die Serververbindung herstellen.

Multithreading-Technologie, parallele Ausführung von Thread-Aufrufen.

Im letzten Artikel wurde erwähnt, dass es zwei Möglichkeiten gibt, Multithreading in Java zu implementieren: die Verwendung der Thread-Klasse und die Verwendung der Runnable-Klasse und die Implementierung der run () -Methode . Im Folgenden wird die Runnable-Klasse verwendet, um die zugehörigen Betriebsfunktionen des Servers zu kapseln. In Kombination mit dem vorherigen Artikel lernen Sie zwei Multithreading-Implementierungsmethoden kennen.

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

Der Server hat viele gleichzeitige Verbindungen von Clients. Die Multithread-Lösung in diesem Fall lautet im Allgemeinen:

  1. Der Haupt-Thread ist nur für das Abhören von Client-Anfragen und das Akzeptieren von Verbindungsanfragen verantwortlich. Ein Thread ist für das Gespräch mit einem Kunden vorgesehen . Das heißt , nachdem eine Kundenanfrage erfolgreich ist, wird ein neuer Thread erstellt, der sich um den Kunden kümmert. Für dieses Schema können Sie die neue Thread-Methode im vorherigen Artikel verwenden, um Threads zu erstellen. Das häufige Erstellen von Threads erfordert jedoch viele Systemressourcen. Diese Methode wird also nicht verwendet.
  2. Bei Servern werden Thread-Pools im Allgemeinen zum Verwalten und Wiederverwenden von Threads verwendet . Innerhalb des Thread-Pools werden mehrere Threads verwaltet. Wenn keine Aufgaben vorhanden sind, befinden sich diese Threads alle in einem Wartezustand. Wenn eine neue Aufgabe vorhanden ist, wird ein inaktiver Thread zur Ausführung zugewiesen. Wenn alle Threads ausgelastet sind, werden neue Aufgaben entweder in die Warteschlange gestellt und warten, oder es wird ein neuer Thread zur Verarbeitung hinzugefügt.

Offensichtlich verwenden wir die zweite Thread-Pool-Methode. Übliche Erstellungsmethoden sind:

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

Der nächste Schritt ist die Auswahl des Typs des Thread-Pools. Die Verwendung des ersten Thread-Pools mit einer festen Anzahl von Threads ist offensichtlich nicht flexibel genug. Der zweite Thread-Pool passt die Größe des Thread-Pools dynamisch an die Anzahl der Aufgaben an. Als kleine gleichzeitige Verwendung ist dies kein großes Problem, wird jedoch in der tatsächlichen Produktionsumgebung nicht verwendet. Wenn die Menge der Parallelität zu groß ist, führt dies häufig zu OutOfMemoryError (OutOfMemoryError). Gemäß unseren Anwendungsszenarien können wir dies verwenden, um den Thread-Pool dynamisch anzupassen.

Verwenden Sie zweitens den Thread-Pool, um serverseitiges Multithreading zu erreichen

1. Single-Threaded-Version

Erstens kann der folgende Code im Vergleich zur vorherigen Single-Thread-Kommunikation nur die Kommunikation zwischen einem einzelnen Benutzer und dem Server realisieren. Wenn mehrere Benutzer mit dem Server kommunizieren, wird sie blockiert.

    //单客户版本,每次只能与一个用户建立通信连接
    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();
                }
            }
        }
    }

 Basierend auf der obigen Analyse wird daher die Single-Thread-Version der Server-Client-Kommunikations- und Dialogfunktionen unabhängig und von einem Thread behandelt. Dadurch wird die Ausführung des Hauptprozesses nicht blockiert. Die spezifische Implementierung ist wie folgt.

 2. Multithread-Version

 

1. Erstellen Sie einen anonymen Handler für die innere Klasse, implementieren Sie die Ausführungsmethode der Runnable-Klasse und setzen Sie den Kommunikationsdialog 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. Verwenden Sie newCachedThreadPool (), um dynamisch einen Thread-Pool zu erstellen

Thread-Pool als Mitgliedsvariable:

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

 Erstellen Sie einen neuen Thread in der Service-Methode des Servers und übergeben Sie ihn zur Verarbeitung an den Thread-Pool.

 

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

3. Demonstration der Kommunikation zwischen mehreren Benutzern und Servern

Wenn der Server zuvor nur Einzelbenutzer-Kommunikationssitzungen unterstützte, wurden die vom neuen Benutzer gesendeten Informationen blockiert und der Server konnte nicht zurückkehren.

Es ist interessant festzustellen, dass das andere Ende die Kommunikation beendet und gleichzeitig das andere Ende sofort die Antwortnachricht vom Server empfängt.

Anhand der vorläufigen Beobachtung der angezeigten Zeit kann beurteilt werden, dass die zuvor gesendeten Informationen im Serverprozess blockiert sind. Nachdem die Verbindung einer Partei getrennt wurde, sendet der Server die blockierten Warteschlangeninformationen an den Client. Was ist das Ergebnis nach Multithreading?

Weitere Erfahrungen in der Bewegtbilddemonstration:

 

Viertens der vollständige Code des Mehrbenutzerservers

/*
 * 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();
    }

}


Zu guter Letzt

In diesem Artikel wird das Problem der serverseitigen Mehrbenutzerkommunikation gelöst und die Realisierung des serverseitigen Multithreading detailliert aufgezeichnet. Ziel ist es, dass mehrere Benutzer (Clients) gleichzeitig Verbindungen herstellen und mit dem Server kommunizieren, Blockierungen vermeiden und die TCP-Socket-Netzwerkkommunikation weiter verbessern können. Verwenden Sie die Java-Multithreading-Technologie, um eine mehrbenutzer- und serverseitige Socket-Kommunikation zu realisieren! Kurz gesagt, es entspricht mehreren Benutzern, die auf Serverressourcen zugreifen. Der Server sollte eine Verbindung mit jedem Client herstellen. Genau wie unsere tägliche Verwendung von QQ-, WeChat- und Video-Clients ist dies ein Beispiel für die Mehrbenutzer-Kommunikation mit dem Server.

Alte Frage, ๑ 乛 ◡ 乛 ๑, es scheint, dass nach Abschluss dieser Frage, was interessantes erreicht werden kann? Bleib hier und denke 3 Sekunden nach!

……

……

……

Das heißt: Um einen Gruppenchatraum zu schaffen, ähnlich wie bei QQ, WeChat-Gruppenchat, können Sie zwischen mehreren Benutzern kommunizieren. Fühlt es sich sehr interessant an?

Kann die Gruppen-Chatroom- Funktion basierend auf der Multithreading-Technologie dieses Artikels zur Erzielung serverseitiger Funktionen für mehrere Benutzer gelöst werden? Warten Sie auf das nächste Update, um diese Funktion zu erreichen!

Wenn Sie der Meinung sind, dass es gut ist, können Sie gerne "mit einem Klick, drei Links" Lesezeichen setzen, folgen, direkt kommentieren, wenn Sie Fragen haben, und austauschen und lernen!

Java-Implementierung der Programmierreihe zur Programmierung von Socket-Kommunikationsnetzen:

  1. Network Socket-Programmierung basierend auf dem UDP-Protokoll (C / S-Kommunikationsfall in Java) [ https://blog.csdn.net/Charzous/article/details/109016215 ]
  2. Netzwerk-Socket-Programmierung basierend auf dem TCP-Protokoll (Java realisiert die C / S-Kommunikation) [ https://blog.csdn.net/Charzous/article/details/109016215 ]
  3. Java-Multithreading zur Realisierung der TCP-Netzwerk-Socket-Programmierung (C / S-Kommunikation) [ https://blog.csdn.net/Charzous/article/details/109283697 ]

Mein CSDN-Blog: https://blog.csdn.net/Charzous/article/details/109440277

Ich denke du magst

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