网络编程
Java 网络编程是实现 Java 程序之间跨网络通信的技术,主要基于 TCP/IP 协议栈,通过 Java 提供的java.net
包实现。以下从核心概念到实际应用详解 Java 网络编程:
一、网络编程基础概念
- IP 地址:标识网络中的设备(如
192.168.1.1
),Java 中用InetAddress
类表示。 - 端口号:标识设备上的进程(0-65535,其中 0-1023 为知名端口,如 HTTP 的 80)。
- 协议:
- TCP:面向连接、可靠传输(三次握手建立连接,四次挥手断开),适合大数据传输(如文件传输)。
- UDP:无连接、不可靠传输(数据可能丢失),速度快,适合实时通信(如视频通话)。
- Socket(套接字):IP + 端口的组合,是网络通信的端点,Java 中通过
Socket
(客户端)和ServerSocket
(TCP 服务器)实现。
二、TCP 编程(面向连接)
TCP 通信需先建立连接,再传输数据,步骤如下:
1. TCP 服务器(ServerSocket)
- 创建
ServerSocket
并绑定端口。 - 调用
accept()
监听客户端连接(阻塞方法)。 - 通过输入流读取客户端数据,输出流发送响应。
- 通信结束后关闭流和 Socket。
2. TCP 客户端(Socket)
- 创建
Socket
并指定服务器 IP 和端口。 - 通过输出流发送数据,输入流接收响应。
- 通信结束后关闭流和 Socket。
示例代码:
// TCP服务器
public class TCPServer {public static void main(String[] args) throws IOException {// 1. 创建服务器Socket,绑定端口8888ServerSocket serverSocket = new ServerSocket(8888);System.out.println("服务器启动,等待客户端连接...");// 2. 监听客户端连接(阻塞)Socket socket = serverSocket.accept();System.out.println("客户端已连接:" + socket.getInetAddress());// 3. 获取输入流(读客户端数据)BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));// 获取输出流(向客户端写数据)PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), true);// 4. 通信过程String msg;while ((msg = br.readLine()) != null) {System.out.println("收到客户端消息:" + msg);pw.println("服务器已收到:" + msg); // 发送响应if ("exit".equals(msg)) break; // 退出条件}// 5. 关闭资源pw.close();br.close();socket.close();serverSocket.close();}
}// TCP客户端
public class TCPClient {public static void main(String[] args) throws IOException {// 1. 连接服务器(IP为localhost,端口8888)Socket socket = new Socket("localhost", 8888);// 2. 获取输出流(向服务器写数据)PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), true);// 获取输入流(读服务器响应)BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));// 从控制台输入BufferedReader consoleBr = new BufferedReader(new InputStreamReader(System.in));// 3. 通信过程String msg;while ((msg = consoleBr.readLine()) != null) {pw.println(msg); // 发送数据到服务器if ("exit".equals(msg)) break;System.out.println("服务器响应:" + br.readLine());}// 4. 关闭资源consoleBr.close();br.close();pw.close();socket.close();}
}
三、UDP 编程(无连接)
UDP 无需建立连接,直接发送数据报(DatagramPacket
),步骤如下:
1. UDP 发送端
- 创建
DatagramSocket
(可指定端口,也可随机分配)。 - 构建
DatagramPacket
(包含数据、长度、目标 IP 和端口)。 - 调用
send()
发送数据报。
2. UDP 接收端
- 创建
DatagramSocket
并绑定端口。 - 创建空
DatagramPacket
用于接收数据。 - 调用
receive()
接收数据(阻塞方法)。
示例代码:
// UDP发送端
public class UDPSender {public static void main(String[] args) throws IOException {// 1. 创建发送端SocketDatagramSocket socket = new DatagramSocket();// 2. 准备数据String msg = "Hello UDP!";byte[] data = msg.getBytes("UTF-8");// 目标地址和端口(localhost:9999)InetAddress address = InetAddress.getByName("localhost");int port = 9999;// 3. 打包数据DatagramPacket packet = new DatagramPacket(data, data.length, address, port);// 4. 发送socket.send(packet);System.out.println("数据已发送");// 5. 关闭socket.close();}
}// UDP接收端
public class UDPReceiver {public static void main(String[] args) throws IOException {// 1. 创建接收端Socket,绑定端口9999DatagramSocket socket = new DatagramSocket(9999);System.out.println("接收端启动,等待数据...");// 2. 创建数据包用于接收(缓冲区大小为1024)byte[] buffer = new byte[1024];DatagramPacket packet = new DatagramPacket(buffer, buffer.length);// 3. 接收数据(阻塞)socket.receive(packet);// 4. 解析数据String msg = new String(packet.getData(), 0, packet.getLength(), "UTF-8");System.out.println("收到来自 " + packet.getAddress() + " 的数据:" + msg);// 5. 关闭socket.close();}
}
四、URL 与 HTTP 编程
Java 通过URL
和URLConnection
类支持 HTTP 等高层协议:
1. URL(统一资源定位符)
表示互联网资源地址(如https://www.example.com/index.html
),可直接读取资源内容。
示例:
public class URLDemo {public static void main(String[] args) throws IOException {URL url = new URL("https://www.example.com");// 打开连接URLConnection conn = url.openConnection();// 获取输入流读取内容try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"))) {String line;while ((line = br.readLine()) != null) {System.out.println(line); // 打印网页内容}}}
}
2. HTTP 客户端(JDK 11+ HttpClient)
JDK 11 引入的HttpClient
支持同步 / 异步 HTTP 请求,替代传统的HttpURLConnection
:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;public class HttpClientDemo {public static void main(String[] args) throws Exception {// 创建客户端HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build();// 创建请求HttpRequest request = HttpRequest.newBuilder().uri(URI.create("https://www.example.com")).GET() // 默认方法.build();// 发送同步请求HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());// 输出响应System.out.println("状态码:" + response.statusCode());System.out.println("响应体:" + response.body());}
}
五、高级特性
多线程服务器:单个服务器同时处理多个客户端连接(为每个客户端创建线程)。
// 多线程TCP服务器示例(简化) public class MultiThreadTCPServer {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8888);while (true) {Socket socket = serverSocket.accept(); // 循环接收客户端// 为每个客户端启动新线程处理new Thread(() -> handleClient(socket)).start();}}private static void handleClient(Socket socket) {// 处理客户端通信(代码同单线程服务器)} }
NIO(非阻塞 IO):基于通道(Channel)和缓冲区(Buffer),支持非阻塞模式,适合高并发场景(如 Netty 框架)。
SSL/TLS 加密:通过
SSLSocket
和SSLServerSocket
实现加密通信,保障数据安全。
六、常见问题与注意事项
- 端口占用:启动服务器时若提示
Address already in use
,需更换端口或杀死占用进程。 - 编码问题:网络传输需统一编码(如 UTF-8),避免中文乱码。
- 资源释放:流和 Socket 需在
finally
中关闭,或使用 try-with-resources 自动关闭。 - 防火墙:确保服务器端口在防火墙中开放,否则客户端无法连接。
总结
Java 网络编程通过 TCP 和 UDP 两种协议实现基础通信,结合URL
和HttpClient
可处理 HTTP 等高层协议。在实际开发中,复杂场景(如高并发)常使用 Netty 等框架简化开发,但理解底层原理(Socket、IO 流)是关键。