Java 网络编程教程_java nio网络编程
第一节:网络协议TCP/UDP/SOCKET 介绍
1.1 网络协议基础
网络协议是计算机网络中数据交换的规则和标准。Java主要支持以下协议:
TCP (Transmission Control Protocol)
- 特点:面向连接、可靠传输、字节流服务
- 优点:数据完整性保证、顺序传输、流量控制
- 缺点:建立连接开销大、传输效率相对较低
- 应用场景:文件传输、邮件发送、网页浏览(HTTP)
UDP (User Datagram Protocol)
- 特点:无连接、不可靠传输、数据报服务
- 优点:传输效率高、延迟低、开销小
- 缺点:不保证数据完整性、可能丢包、无序到达
- 应用场景:视频流、语音通话、在线游戏
SOCKET 套接字
- 定义:网络通信的端点,包含IP地址和端口号
- 类型:
- 流套接字(SOCK_STREAM):基于TCP
- 数据报套接字(SOCK_DGRAM):基于UDP
- 作用:应用程序通过网络进行数据交换的接口
1.2 SOCKET 与 TCP/UDP 的关系
1.2.1 SOCKET 是编程接口,TCP/UDP 是传输协议
关键关系:
- SOCKET 是操作系统提供的**编程接口**(API)
- TCP/UDP 是网络传输的协议标准
- SOCKET 封装了底层TCP/UDP协议的实现细节
// TCP Socket - 基于TCP协议的Socket编程
Socket tcpSocket = new Socket("localhost", 8080);
// UDP Socket - 基于UDP协议的Socket编程
DatagramSocket udpSocket = new DatagramSocket(8080);
1.2.4 协议选择对比
特性 | TCP Socket | UDP Socket |
连接方式 | 面向连接 | 无连接 |
数据传输 | 字节流 | 数据报 |
可靠性 | 自动重传、确认机制 | 需要应用层处理 |
顺序性 | 保证数据顺序 | 不保证顺序 |
开销 | 较大 | 较小 |
适用场景 | 文件传输、Web请求 | 实时音视频、游戏 |
1.3 Java网络编程核心类
// TCP相关
ServerSocket // 服务器端套接字
Socket // 客户端套接字
// UDP相关
DatagramSocket // UDP套接字
DatagramPacket // 数据包
// 通用
InetAddress // IP地址处理
第二节:TCP Socket 示例 - 双向通信
2.1 TCP 服务器端代码
import java.io.*;
import java.net.*;
public class TCPServer {
public static void main(String[] args) {
final int PORT = 8888;
try (ServerSocket serverSocket = new ServerSocket(PORT)) {
System.out.println("TCP服务器启动,等待客户端连接...");
Socket clientSocket = serverSocket.accept();
System.out.println("客户端连接成功: " + clientSocket.getInetAddress());
// 接收客户端消息
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
String clientMessage = in.readLine();
System.out.println("收到客户端消息: " + clientMessage);
// 发送响应
PrintWriter out = new PrintWriter(
clientSocket.getOutputStream(), true);
out.println("Hello,Server");
System.out.println("消息发送完成");
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.2 TCP 客户端代码
import java.io.*;
import java.net.*;
public class TCPClient {
public static void main(String[] args) {
final String SERVER_IP = "localhost";
final int PORT = 8888;
try (Socket socket = new Socket(SERVER_IP, PORT)) {
System.out.println("连接TCP服务器成功");
// 发送消息
PrintWriter out = new PrintWriter(
socket.getOutputStream(), true);
out.println("Hello,Client");
// 接收响应
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String serverResponse = in.readLine();
System.out.println("收到服务器响应: " + serverResponse);
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.3 TCP 运行步骤
2.4 TCP 预期输出
服务器端输出:
TCP服务器启动,等待客户端连接...
客户端连接成功: /127.0.0.1
收到客户端消息: Hello,Client
消息发送完成
客户端输出:
连接TCP服务器成功
收到服务器响应: Hello,Server
第三节:UDP Socket 示例 - 数据报通信
3.1 UDP 服务器端代码
import java.net.*;
public class UDPServer {
public static void main(String[] args) {
final int PORT = 8888;
try (DatagramSocket serverSocket = new DatagramSocket(PORT)) {
System.out.println("UDP服务器启动,监听端口: " + PORT);
byte[] receiveBuffer = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);
serverSocket.receive(receivePacket);
String clientMessage = new String(receivePacket.getData(), 0, receivePacket.getLength());
System.out.println("收到客户端消息: " + clientMessage);
System.out.println("客户端地址: " + receivePacket.getAddress().getHostAddress());
String responseMessage = "hello,udp i am server";
byte[] sendBuffer = responseMessage.getBytes();
DatagramPacket sendPacket = new DatagramPacket(
sendBuffer,
sendBuffer.length,
receivePacket.getAddress(),
receivePacket.getPort()
);
serverSocket.send(sendPacket);
System.out.println("已向客户端发送响应");
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.2 UDP 客户端代码
import java.net.*;
public class UDPClient {
public static void main(String[] args) {
final String SERVER_IP = "localhost";
final int PORT = 8888;
try (DatagramSocket clientSocket = new DatagramSocket()) {
System.out.println("UDP客户端启动");
String message = "hello,udp i am client";
byte[] sendBuffer = message.getBytes();
InetAddress serverAddress = InetAddress.getByName(SERVER_IP);
DatagramPacket sendPacket = new DatagramPacket(
sendBuffer,
sendBuffer.length,
serverAddress,
PORT
);
clientSocket.send(sendPacket);
System.out.println("已向服务器发送消息: " + message);
byte[] receiveBuffer = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);
clientSocket.setSoTimeout(3000);
clientSocket.receive(receivePacket);
String serverResponse = new String(receivePacket.getData(), 0, receivePacket.getLength());
System.out.println("收到服务器响应: " + serverResponse);
} catch (SocketTimeoutException e) {
System.out.println("接收超时,服务器可能未响应");
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.4 UDP 预期输出
服务器端输出:
UDP服务器启动,监听端口: 8888
收到客户端消息: hello,udp i am client
客户端地址: 127.0.0.1
已向客户端发送响应
客户端输出:
UDP客户端启动
已向服务器发送消息: hello,udp i am client
收到服务器响应: hello,udp i am server
第四节:TCP vs UDP 对比总结
4.1 编程模型对比
方面 | TCP Socket | UDP Socket |
连接建立 | 需要accept()和connect() | 无连接建立过程 |
数据传输 | 使用InputStream/OutputStream | 使用DatagramPacket |
数据边界 | 字节流,无边界 | 数据报,有边界 |
可靠性 | 自动处理重传和确认 | 需要手动处理可靠性 |
性能 | 相对较慢 | 相对较快 |
4.2 选择建议
选择TCP当:
- 需要可靠的数据传输
- 数据完整性很重要
- 传输大量数据
- 需要维护持久连接
选择UDP当:
- 实时性要求高于可靠性
- 传输小量数据
- 需要广播或多播功能
- 应用层自己处理可靠性
4.3 注意事项
- 端口冲突:TCP和UDP可以使用相同的端口号,不会冲突
- 资源释放:确保正确关闭所有资源
- 异常处理:网络操作必须处理IOException
- 超时设置:合理设置连接和读取超时
第五节:扩展练习
5.1 多客户端TCP服务器
// 多线程TCP服务器示例
while (true) {
Socket clientSocket = serverSocket.accept();
new Thread(() -> {
// 处理客户端通信
}).start();
}
5.2 UDP广播示例
// UDP广播发送
InetAddress broadcastAddress = InetAddress.getByName("255.255.255.255");
DatagramPacket packet = new DatagramPacket(data, data.length, broadcastAddress, port);
socket.send(packet);
5.3 文件传输
基于TCP Socket实现文件传输功能
第六节:常见问题解答
Q1: 为什么UDP不需要建立连接?
A: UDP是无连接协议,每个数据包都是独立的,不需要维护连接状态。
Q2: TCP和UDP可以同时使用同一个端口吗?
A: 可以,TCP和UDP的端口空间是独立的。
Q3: 如何选择TCP还是UDP?
A: 根据应用需求选择:需要可靠性选TCP,需要实时性选UDP。
Q4: 为什么UDP可能更适合实时应用?
A: UDP延迟低,没有重传机制,更适合实时音视频传输。
总结
本教程完整介绍了:
- TCP和UDP协议的基本原理和区别
- Java中TCP和UDP Socket编程的实现
- 完整的双向通信示例代码
- 两种协议的适用场景和选择建议
- 实际编程中的注意事项