授课语音

第 2 课:服务端架构搭建与基础功能实现

目标:完成服务端架构搭建,实现基本的客户端连接功能,能够处理多个客户端的连接请求。


1. 服务端搭建

1.1 创建服务端主类,监听客户端连接

服务端的职责是等待客户端的连接并处理这些连接。我们需要创建一个服务端主类来启动服务端,并监听客户端的连接请求。在 Java 中,ServerSocket 是用来实现服务端监听功能的类。通过 ServerSocket,服务端可以绑定一个指定端口,等待客户端的连接。

代码案例:服务端主类

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) {
        // 创建ServerSocket实例,监听端口8080
        try (ServerSocket serverSocket = new ServerSocket(8080)) {
            System.out.println("服务端启动,等待客户端连接...");

            // 不断循环,接收客户端的连接请求
            while (true) {
                // accept()方法阻塞,直到有客户端连接过来
                Socket clientSocket = serverSocket.accept();
                System.out.println("客户端连接成功:" + clientSocket.getInetAddress());

                // 为每个客户端创建一个新的线程来处理通信
                new ClientHandler(clientSocket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

详细注释解释:

  1. 我们首先创建了一个 ServerSocket 实例,监听 8080 端口,ServerSocket 会一直等待来自客户端的连接。
  2. serverSocket.accept() 会阻塞,直到有客户端请求连接。每当有客户端连接时,accept() 方法返回一个 Socket 对象,这个对象代表了与客户端的通信通道。
  3. 每次接收到客户端连接后,服务端都会创建一个新的线程 ClientHandler 来处理该客户端的通信,这样服务端就可以同时处理多个客户端。

1.2 使用多线程处理多个客户端连接

由于服务端需要同时处理多个客户端连接,采用多线程模型可以确保每个客户端有独立的处理逻辑。每当服务端接受到一个新的客户端连接时,都会为该客户端启动一个新的线程。这个线程的任务就是与该客户端进行通信,接收消息并返回消息。


2. Socket 编程基础

2.1 创建 ServerSocket

ServerSocket 是 Java 中实现服务端功能的核心类。它用于监听指定端口上的客户端请求,并为每个连接创建一个 Socket 对象,通过 Socket 对象与客户端进行通信。

代码案例:创建 ServerSocket

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) {
        try {
            // 创建ServerSocket,指定监听的端口
            ServerSocket serverSocket = new ServerSocket(8080);
            System.out.println("服务端已启动,等待客户端连接...");

            // 等待客户端连接
            Socket socket = serverSocket.accept();
            System.out.println("客户端连接成功:" + socket.getInetAddress());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

详细注释解释:

  • 使用 new ServerSocket(8080) 创建一个服务端套接字,监听 8080 端口。这个端口是服务端用于接收客户端连接的入口。
  • accept() 方法阻塞当前线程,直到有客户端通过 Socket 发起连接请求。连接建立后,accept() 方法返回一个 Socket 对象,代表客户端与服务端之间的通信通道。

2.2 多线程模型:为每个客户端创建一个线程处理通信

由于服务端需要同时处理多个客户端的连接请求,采用多线程模型能够确保每个客户端的通信不会干扰其他客户端。为此,我们创建一个新的线程类 ClientHandler,每当有客户端连接时,服务端都会启动一个新的 ClientHandler 线程来与该客户端进行通信。

代码案例:ClientHandler 类

import java.io.*;
import java.net.Socket;

public class ClientHandler extends Thread {
    private Socket socket;

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

    @Override
    public void run() {
        try {
            // 获取客户端的输入流
            BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String message;
            
            // 循环读取客户端发送的消息
            while ((message = input.readLine()) != null) {
                System.out.println("客户端发送的消息:" + message);
                // 可以在这里处理接收到的消息,如转发或回复给客户端
            }

            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

详细注释解释:

  • ClientHandler 类继承了 Thread 类,表示这是一个独立的线程。
  • run() 方法中,首先通过 getInputStream() 获取客户端的输入流,读取客户端发送的消息。
  • 然后使用 BufferedReader 来逐行读取客户端发送的消息,直到客户端关闭连接。
  • socket.close() 用来关闭与客户端的连接。

3. 初步测试

3.1 编写简单的客户端进行连接测试

为了测试服务端是否能正确接收多个客户端的连接,我们需要编写一个简单的客户端程序。客户端通过 Socket 连接到服务端的指定端口,并向服务端发送一条消息。

代码案例:简单客户端

import java.io.*;
import java.net.Socket;

public class Client {
    public static void main(String[] args) {
        try {
            // 连接到服务端的8080端口
            Socket socket = new Socket("localhost", 8080);
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            // 向服务端发送消息
            out.println("Hello, Server!");

            // 读取服务端的响应
            String response = in.readLine();
            System.out.println("服务端响应:" + response);

            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

详细注释解释:

  • 客户端使用 new Socket("localhost", 8080) 连接到本地服务端的 8080 端口。
  • 通过 PrintWriter 将消息发送给服务端,BufferedReader 用于接收服务端的响应。
  • 客户端发送一条简单的消息 "Hello, Server!",并输出服务端的响应。

3.2 确保服务端能够接受多个客户端的连接请求

我们可以启动多个客户端实例来模拟多个用户同时连接服务端。每个客户端会向服务端发送消息,并接收服务端的响应。服务端能够同时处理多个客户端的请求,验证了多线程模型的正确性。


总结

在本课中,我们完成了服务端架构的搭建,并实现了基本的客户端连接功能。通过 ServerSocket 监听客户端连接,使用多线程为每个客户端提供独立的通信通道。通过测试,我们确保服务端能够接收并处理多个客户端的连接请求。接下来的课程中,我们将进一步完善服务端的消息处理功能,并增加更多的聊天功能。

去1:1私密咨询

系列课程: