📜  Java中的多线程服务器

📅  最后修改于: 2022-05-13 01:55:16.745000             🧑  作者: Mango

Java中的多线程服务器

先决条件: Java套接字编程

多线程服务器:具有多个线程的服务器称为多线程服务器。当客户端发送请求时,会生成一个线程,用户可以通过该线程与服务器进行通信。我们需要生成多个线程来同时接受来自多个客户端的多个请求。

多线程服务器

多线程服务器的优点:

  • 快速高效:多线程服务器可以快速高效地响应不断增加的客户端查询。
  • 用户等待时间减少:在单线程服务器中,其他用户必须等到正在运行的进程完成,但在多线程服务器中,所有用户都可以一次得到响应,因此用户不必等待其他进程完成.
  • 线程相互独立:任意两个线程之间没有关系。当客户端连接时,每次都会生成一个新线程。
  • 一个线程中的问题不会影响其他线程:如果任何一个线程中发生任何错误,则不会干扰其他线程,所有其他进程保持正常运行。在单线程服务器中,如果线程中出现任何问题,所有其他客户端都必须等待。

多线程服务器的缺点:

  • 代码复杂:多线程服务器的代码很难写。这些程序不容易创建
  • 调试难:分析错误的主要原因和来源很困难。

快速概览

我们创建了两个Java文件Client.java Java服务器。Java客户端文件只包含一个类Client (用于创建客户端)。服务器文件有两个类, Server (创建服务器)和ClientHandler (使用多线程处理客户端)。

多线程服务器编程

客户端程序:客户端可以使用此代码与服务器通信。这涉及

  1. 建立套接字连接
  2. 沟通
Java
import java.io.*;
import java.net.*;
import java.util.*;
  
// Client class
class Client {
    
    // driver code
    public static void main(String[] args)
    {
        // establish a connection by providing host and port
        // number
        try (Socket socket = new Socket("localhost", 1234)) {
            
            // writing to server
            PrintWriter out = new PrintWriter(
                socket.getOutputStream(), true);
  
            // reading from server
            BufferedReader in
                = new BufferedReader(new InputStreamReader(
                    socket.getInputStream()));
  
            // object of scanner class
            Scanner sc = new Scanner(System.in);
            String line = null;
  
            while (!"exit".equalsIgnoreCase(line)) {
                
                // reading from user
                line = sc.nextLine();
  
                // sending the user input to server
                out.println(line);
                out.flush();
  
                // displaying server reply
                System.out.println("Server replied "
                                   + in.readLine());
            }
            
            // closing the scanner object
            sc.close();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}


Java
import java.io.*;
import java.net.*;
  
// Server class
class Server {
    public static void main(String[] args)
    {
        ServerSocket server = null;
  
        try {
  
            // server is listening on port 1234
            server = new ServerSocket(1234);
            server.setReuseAddress(true);
  
            // running infinite loop for getting
            // client request
            while (true) {
  
                // socket object to receive incoming client
                // requests
                Socket client = server.accept();
  
                // Displaying that new client is connected
                // to server
                System.out.println("New client connected"
                                   + client.getInetAddress()
                                         .getHostAddress());
  
                // create a new thread object
                ClientHandler clientSock
                    = new ClientHandler(client);
  
                // This thread will handle the client
                // separately
                new Thread(clientSock).start();
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            if (server != null) {
                try {
                    server.close();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
  
    // ClientHandler class
    private static class ClientHandler implements Runnable {
        private final Socket clientSocket;
  
        // Constructor
        public ClientHandler(Socket socket)
        {
            this.clientSocket = socket;
        }
  
        public void run()
        {
            PrintWriter out = null;
            BufferedReader in = null;
            try {
                    
                  // get the outputstream of client
                out = new PrintWriter(
                    clientSocket.getOutputStream(), true);
  
                  // get the inputstream of client
                in = new BufferedReader(
                    new InputStreamReader(
                        clientSocket.getInputStream()));
  
                String line;
                while ((line = in.readLine()) != null) {
  
                    // writing the received message from
                    // client
                    System.out.printf(
                        " Sent from the client: %s\n",
                        line);
                    out.println(line);
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }
            finally {
                try {
                    if (out != null) {
                        out.close();
                    }
                    if (in != null) {
                        in.close();
                        clientSocket.close();
                    }
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


服务器端程序:当新客户端连接时,他将消息发送到服务器。

1.Server类:Server端涉及的步骤与Java中的Socket Programming一文类似,略有改动,获取流和端口号后创建线程对象。

  • 建立连接:服务器套接字对象被初始化,在一个 while 循环中,套接字对象不断地接受传入的连接。
  • 获取流:从当前请求的套接字对象中提取输入流对象和输出流对象。
  • 创建处理程序对象:获取流和端口号后,使用这些参数创建一个新的 clientHandler 对象(上述类)。
  • 调用start()方法:在这个新创建的线程对象上调用 start() 方法。

2. ClientHandler 类:由于我们将为每个请求使用单独的线程,让我们了解实现 Runnable 的ClientHandler类的工作和实现。此类的对象充当新线程的 Runnable 目标。

  • 首先,该类实现了 Runnable 接口,以便在创建新线程时可以将其作为 Runnable 目标传递。
  • 其次,这个类的构造函数带有一个参数,它可以唯一标识任何传入的请求,即一个Socket
  • 在这个类的run()方法中,它读取客户端的消息并回复。

Java

import java.io.*;
import java.net.*;
  
// Server class
class Server {
    public static void main(String[] args)
    {
        ServerSocket server = null;
  
        try {
  
            // server is listening on port 1234
            server = new ServerSocket(1234);
            server.setReuseAddress(true);
  
            // running infinite loop for getting
            // client request
            while (true) {
  
                // socket object to receive incoming client
                // requests
                Socket client = server.accept();
  
                // Displaying that new client is connected
                // to server
                System.out.println("New client connected"
                                   + client.getInetAddress()
                                         .getHostAddress());
  
                // create a new thread object
                ClientHandler clientSock
                    = new ClientHandler(client);
  
                // This thread will handle the client
                // separately
                new Thread(clientSock).start();
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            if (server != null) {
                try {
                    server.close();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
  
    // ClientHandler class
    private static class ClientHandler implements Runnable {
        private final Socket clientSocket;
  
        // Constructor
        public ClientHandler(Socket socket)
        {
            this.clientSocket = socket;
        }
  
        public void run()
        {
            PrintWriter out = null;
            BufferedReader in = null;
            try {
                    
                  // get the outputstream of client
                out = new PrintWriter(
                    clientSocket.getOutputStream(), true);
  
                  // get the inputstream of client
                in = new BufferedReader(
                    new InputStreamReader(
                        clientSocket.getInputStream()));
  
                String line;
                while ((line = in.readLine()) != null) {
  
                    // writing the received message from
                    // client
                    System.out.printf(
                        " Sent from the client: %s\n",
                        line);
                    out.println(line);
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }
            finally {
                try {
                    if (out != null) {
                        out.close();
                    }
                    if (in != null) {
                        in.close();
                        clientSocket.close();
                    }
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

脚步:

  • 编译客户端和服务器程序。
  • 首先运行服务器,然后运行客户端。

输出