跳转到内容

Java ServerSocket类

来自代码酷

Java ServerSocket类[编辑 | 编辑源代码]

ServerSocket 类是 Java 网络编程中的核心类之一,用于在服务器端监听客户端的连接请求。它是实现 TCP/IP 协议通信的基础,允许服务器程序等待并接受来自客户端的连接。

概述[编辑 | 编辑源代码]

ServerSocket 类位于 `java.net` 包中,主要功能是:

  • 绑定到特定端口监听连接请求
  • 接受客户端连接并返回 Socket 对象
  • 设置连接超时等参数

一个典型的服务器端工作流程如下: 1. 创建 ServerSocket 实例并绑定到端口 2. 调用 accept() 方法等待客户端连接 3. 接受连接后通过返回的 Socket 对象进行通信 4. 关闭连接

sequenceDiagram participant Server participant Client Server->>Server: 创建ServerSocket(port) Server->>Server: accept() 阻塞等待 Client->>Server: 连接请求 Server->>Client: 接受连接 Server->>Client: 建立Socket通信

构造函数[编辑 | 编辑源代码]

ServerSocket 提供了多个构造函数:

// 绑定到指定端口,backlog为连接队列长度
ServerSocket(int port, int backlog)

// 绑定到指定端口和本地IP地址
ServerSocket(int port, int backlog, InetAddress bindAddr)

// 不绑定端口,需要后续调用bind()
ServerSocket()

核心方法[编辑 | 编辑源代码]

基本操作[编辑 | 编辑源代码]

// 绑定到指定地址和端口
void bind(SocketAddress endpoint)

// 等待客户端连接,返回Socket对象
Socket accept()

// 关闭ServerSocket
void close()

配置方法[编辑 | 编辑源代码]

// 设置SO_TIMEOUT(毫秒)
void setSoTimeout(int timeout)

// 获取SO_TIMEOUT值
int getSoTimeout()

// 设置SO_REUSEADDR选项
void setReuseAddress(boolean on)

代码示例[编辑 | 编辑源代码]

基础服务器示例[编辑 | 编辑源代码]

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

public class SimpleServer {
    public static void main(String[] args) throws IOException {
        // 在端口8080上创建服务器
        try (ServerSocket serverSocket = new ServerSocket(8080)) {
            System.out.println("服务器启动,等待连接...");
            
            // 接受客户端连接
            Socket clientSocket = serverSocket.accept();
            System.out.println("客户端已连接: " + 
                clientSocket.getInetAddress());
                
            // 获取输入输出流
            PrintWriter out = new PrintWriter(
                clientSocket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(
                new InputStreamReader(clientSocket.getInputStream()));
                
            // 通信循环
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                System.out.println("收到: " + inputLine);
                out.println("服务器回应: " + inputLine);
            }
        }
    }
}

多线程服务器示例[编辑 | 编辑源代码]

处理多个客户端连接:

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

public class MultiThreadedServer {
    public static void main(String[] args) throws IOException {
        try (ServerSocket serverSocket = new ServerSocket(8080)) {
            System.out.println("多线程服务器启动...");
            
            while (true) {
                Socket clientSocket = serverSocket.accept();
                // 为每个客户端创建新线程
                new Thread(new ClientHandler(clientSocket)).start();
            }
        }
    }
}

class ClientHandler implements Runnable {
    private final Socket clientSocket;
    
    public ClientHandler(Socket socket) {
        this.clientSocket = socket;
    }
    
    public void run() {
        try (
            PrintWriter out = new PrintWriter(
                clientSocket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(
                new InputStreamReader(clientSocket.getInputStream()))
        ) {
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                System.out.println("线程" + Thread.currentThread().getId() + 
                    " 收到: " + inputLine);
                out.println("处理结果: " + inputLine.toUpperCase());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

高级特性[编辑 | 编辑源代码]

超时处理[编辑 | 编辑源代码]

ServerSocket 可以设置超时时间,防止 accept() 无限期阻塞:

ServerSocket serverSocket = new ServerSocket(8080);
serverSocket.setSoTimeout(5000); // 5秒超时

try {
    Socket clientSocket = serverSocket.accept();
    // 处理连接
} catch (SocketTimeoutException e) {
    System.out.println("接受连接超时");
}

端口复用[编辑 | 编辑源代码]

使用 SO_REUSEADDR 选项可以快速重启绑定相同端口的服务器:

ServerSocket serverSocket = new ServerSocket();
serverSocket.setReuseAddress(true);
serverSocket.bind(new InetSocketAddress(8080));

实际应用场景[编辑 | 编辑源代码]

案例:在线聊天服务器 ServerSocket 常用于实现聊天服务器,处理多个客户端的消息转发:

classDiagram class ChatServer { -ServerSocket serverSocket -List<ClientHandler> clients +startServer() +broadcastMessage() } class ClientHandler { -Socket clientSocket -String username +run() +sendMessage() } ChatServer "1" *-- "*" ClientHandler

实现要点: 1. 主线程接受新连接 2. 为每个客户端创建独立线程 3. 维护客户端列表 4. 实现消息广播功能

性能考虑[编辑 | 编辑源代码]

  • 连接队列: backlog 参数控制未处理连接的最大数量
  • 线程池: 使用 ExecutorService 替代直接创建线程
  • NIO: 高并发场景考虑使用 ServerSocketChannel

计算公式:最大并发连接数 ≈ 线程池大小 × 单个请求处理时间

C=Tt 其中:

  • C = 并发能力
  • T = 线程池大小
  • t = 平均请求处理时间

常见问题[编辑 | 编辑源代码]

Q: 为什么 accept() 会阻塞? A: accept() 是阻塞调用,直到有客户端连接才会返回。可以使用 setSoTimeout() 设置超时。

Q: 如何处理"Address already in use"错误? A: 设置 SO_REUSEADDR 选项或等待 TCP 的 TIME_WAIT 状态结束(通常2-4分钟)。

Q: 服务器如何优雅关闭? A: 在关闭 ServerSocket 前需要处理所有客户端连接,可以使用标志变量控制循环退出。

最佳实践[编辑 | 编辑源代码]

1. 始终在 finally 块中关闭 ServerSocket 2. 使用 try-with-resources 确保资源释放 3. 为生产环境配置适当的 backlog 值(默认50可能不足) 4. 考虑使用线程池管理客户端连接 5. 实现适当的错误处理和日志记录

总结[编辑 | 编辑源代码]

ServerSocket 是 Java 网络编程的基础类,理解其工作原理对于开发服务器应用至关重要。从简单的单线程服务器到复杂的多线程实现,ServerSocket 提供了构建各种网络服务的基础能力。在实际开发中,应结合具体需求选择合适的实现方式,并注意资源管理和性能优化。