JavaEE 网络编程套接字详解与实战示例
、套接字(Socket)是什么?
套接字是网络通信的“端点”,就像打电话需要手机一样,网络通信需要套接字建立连接。
两种类型:
- TCP套接字:可靠传输(类似打电话,需先拨通)
- UDP套接字:快速传输(类似发短信,无需确认对方收到)
二、TCP 套接字编程
1. 服务端开发步骤
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class TcpServer {public static void main(String[] args) {try (ServerSocket serverSocket = new ServerSocket(8080)) { // 1. 绑定端口System.out.println("服务器启动,等待连接...");while (true) {Socket clientSocket = serverSocket.accept(); // 2. 阻塞等待客户端连接System.out.println("客户端连接成功: " + clientSocket.getInetAddress());// 3. 处理客户端请求(单线程版)try (InputStream is = clientSocket.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(is));OutputStream os = clientSocket.getOutputStream();PrintWriter writer = new PrintWriter(os)) {String request = reader.readLine(); // 读取客户端消息System.out.println("收到请求: " + request);// 返回响应writer.println("服务器响应: " + request.toUpperCase());writer.flush(); // 强制发送数据}}} catch (IOException e) {e.printStackTrace();}}
}
重点解析:
ServerSocket(8080)
:绑定端口 8080,类似开通电话线路。accept()
:阻塞等待客户端连接,返回客户端 Socket 对象。- 单线程问题:一次只能处理一个客户端,需优化为多线程(见下文)。
2. 客户端开发步骤
import java.io.*;
import java.net.Socket;public class TcpClient {public static void main(String[] args) {try (Socket socket = new Socket("localhost", 8080); // 1. 连接服务器PrintWriter writer = new PrintWriter(socket.getOutputStream());BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in))) {System.out.print("输入消息: ");String message = consoleReader.readLine();writer.println(message); // 2. 发送消息writer.flush();String response = reader.readLine(); // 3. 读取响应System.out.println("服务器响应: " + response);} catch (IOException e) {e.printStackTrace();}}
}
重点解析:
new Socket("IP", 端口)
:主动连接服务器。flush()
:确保数据立即发送(缓冲区可能延迟发送)。
3. 多线程优化服务端
// 修改服务端代码中的处理部分
while (true) {Socket clientSocket = serverSocket.accept();new Thread(() -> {try (InputStream is = clientSocket.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(is));OutputStream os = clientSocket.getOutputStream();PrintWriter writer = new PrintWriter(os)) {String request = reader.readLine();System.out.println("收到请求: " + request);writer.println("响应: " + request.toUpperCase());writer.flush();} catch (IOException e) {e.printStackTrace();}}).start();
}
作用:每个客户端连接分配独立线程,支持并发处理。
三、UDP 套接字编程
1. 服务端开发
import java.net.DatagramPacket;
import java.net.DatagramSocket;public class UdpServer {public static void main(String[] args) {try (DatagramSocket socket = new DatagramSocket(8080)) { // 1. 绑定端口byte[] buffer = new byte[1024];DatagramPacket packet = new DatagramPacket(buffer, buffer.length);while (true) {socket.receive(packet); // 2. 接收数据包(阻塞)String message = new String(packet.getData(), 0, packet.getLength());System.out.println("收到消息: " + message);}} catch (IOException e) {e.printStackTrace();}}
}
2. 客户端开发
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;public class UdpClient {public static void main(String[] args) {try (DatagramSocket socket = new DatagramSocket()) { // 1. 随机端口String message = "Hello UDP";byte[] data = message.getBytes();// 2. 构建数据包(目标地址+端口)DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("localhost"), 8080);socket.send(packet); // 3. 发送数据包} catch (IOException e) {e.printStackTrace();}}
}
重点解析:
- UDP 无需建立连接,直接发送数据包。
DatagramPacket
包含数据和目标地址信息。
四、JavaEE 中的网络编程
虽然 JavaEE 主要面向 Web 应用(如 Servlet/JSP),但底层仍依赖 Socket:
- HTTP 协议:基于 TCP,Servlet 容器(如 Tomcat)内部使用 Socket 处理请求。
- WebSocket:全双工通信协议,适用于实时应用(聊天室、股票行情)。
示例:Servlet 处理 HTTP 请求
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {protected void doGet(HttpServletRequest req, HttpServletResponse resp) {resp.getWriter().println("Hello from Servlet!"); // 通过TCP响应}
}
五、核心总结
-
TCP vs UDP:
- TCP:可靠、面向连接(文件传输、网页)
- UDP:快速、无连接(视频流、实时游戏)
-
关键类:
- TCP:
ServerSocket
(服务端)、Socket
(客户端) - UDP:
DatagramSocket
、DatagramPacket
- TCP:
-
开发步骤:
- TCP服务端:绑定端口 → 等待连接 → 处理请求
- TCP客户端:连接服务端 → 发送/接收数据
- UDP:构建数据包 → 发送/接收
-
注意事项:
- 端口冲突:确保端口未被占用(如 8080、3306)
- 资源释放:使用
try-with-resources
自动关闭流 - 多线程:TCP 服务端需处理并发连接