java.net
包的Socket
和ServerSocket
类,客户端通过创建Socket连接服务器指定端口,服务器用ServerSocket监听端口并通过accept()
接收连接,双方通过getInputStream()
和getOutputStream()
获取IO流进行数据传输,通信完毕需关闭连接。Java套接字通信实现详解
套接字通信核心概念
套接字(Socket)是网络通信的基石,充当不同主机间进程双向通信的端点,Java通过java.net
包提供完整的套接字API支持,主要分为两类:
- TCP套接字:面向连接(可靠传输)
- 使用
Socket
(客户端)和ServerSocket
(服务端) - 适用场景:文件传输、网页访问等需数据完整性的场景
- 使用
- UDP套接字:无连接(高速传输)
- 使用
DatagramSocket
和DatagramPacket
- 适用场景:视频流、实时游戏等容忍丢包的场景
- 使用
TCP套接字实现步骤(含代码)
服务端实现流程:
try (ServerSocket serverSocket = new ServerSocket(8888)) { System.out.println("服务端启动,监听8888端口..."); // 等待客户端连接 try (Socket clientSocket = serverSocket.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)) { // 读取客户端数据 String request = in.readLine(); System.out.println("收到客户端消息:" + request); // 发送响应 out.println("服务端响应: " + request.toUpperCase()); } } catch (IOException e) { e.printStackTrace(); }
客户端实现流程:
try (Socket socket = new Socket("localhost", 8888); 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); } catch (UnknownHostException e) { System.err.println("未知主机: " + e.getMessage()); } catch (IOException e) { System.err.println("I/O错误: " + e.getMessage()); }
关键对象解析:
ServerSocket.accept()
:阻塞等待客户端连接,返回通信SocketSocket.getInputStream()
/getOutputStream()
:获取字节流- 装饰器模式:使用
BufferedReader
/PrintWriter
简化文本操作
UDP套接字实现(含代码)
发送方实现:
// 创建UDP套接字(随机端口) try (DatagramSocket socket = new DatagramSocket()) { String message = "UDP测试数据"; byte[] buffer = message.getBytes(); // 构建数据包(目标地址+端口) InetAddress address = InetAddress.getByName("localhost"); DatagramPacket packet = new DatagramPacket(buffer, buffer.length, address, 9999); // 发送数据包 socket.send(packet); System.out.println("UDP消息已发送"); }
接收方实现:
try (DatagramSocket socket = new DatagramSocket(9999)) { byte[] buffer = new byte[1024]; DatagramPacket packet = new DatagramPacket(buffer, buffer.length); // 阻塞接收数据 socket.receive(packet); // 解析数据 String received = new String(packet.getData(), 0, packet.getLength()); System.out.println("收到UDP消息: " + received + " 来自: " + packet.getAddress()); }
关键特性:
- 无连接:无需建立持久链接
- 数据包模式:每次发送独立数据包(最大64KB)
- 不可靠性:可能丢包或乱序
最佳实践与常见问题
-
资源管理
- 使用try-with-resources确保Socket关闭
- 避免端口占用:服务停止后立即释放端口
// 设置重用地址选项(解决TIME_WAIT状态占用) serverSocket.setReuseAddress(true);
-
性能优化
- TCP粘包处理:定义消息边界(如长度前缀)
// 消息格式:4字节长度头 + 实际数据 DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); dos.writeInt(data.length); // 写入长度头 dos.write(data); // 写入实际数据
- UDP超时设置:防止
receive()
永久阻塞socket.setSoTimeout(3000); // 3秒超时
- TCP粘包处理:定义消息边界(如长度前缀)
-
典型错误处理
ConnectException
:检查目标端口是否开放BindException
:端口被占用(更换端口或结束占用进程)- 防火墙拦截:开放对应端口权限
协议选择建议
特性 | TCP | UDP |
---|---|---|
可靠性 | ✅ 数据完整保序 | ❌ 可能丢包乱序 |
速度 | 较慢(三次握手) | 极快(无连接开销) |
连接方式 | 点对点持久连接 | 支持广播/多播 |
适用场景 | 金融交易、API调用 | 视频会议、DNS查询 |
选择原则:优先TCP保证数据安全;当延迟敏感且可容忍丢包时选UDP。
安全增强方案
- 使用SSL/TLS加密:
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault(); SSLSocket sslSocket = (SSLSocket) factory.createSocket("host", port);
- 验证主机名:
SSLParameters params = new SSLParameters(); params.setEndpointIdentificationAlgorithm("HTTPS"); sslSocket.setSSLParameters(params);
引用说明:
- Oracle官方文档:Java Networking
- RFC 793:TCP协议规范
- RFC 768:UDP协议规范
- 安全实践参考:OWASP传输层保护建议
本文代码基于Java 17编写,核心API保持向下兼容至Java 8,实际部署需考虑线程池管理(C10K问题)、心跳机制等进阶设计。
原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/33429.html