文章目录
UDP通信
UDP 通信的基本概念
- 无连接:UDP是一种无连接协议,发送数据之前不需要建立连接。
- 不可靠:UDP不保证数据包的可靠传输,数据包可能会丢失。
- 轻量级:由于不需要维护连接状态,UDP比TCP更轻量级。
- 广播和多播:UDP支持广播和多播,适合于需要向多个接收者发送消息的应用场景。
UDP 是无连接的,所以我们不需要先建立连接,只需要指定 IP 和端口号。
Java 中的 UDP 编程
Java 通过 DatagramSocket
和 DatagramPacket
类可以实现 UDP 通信:
-
发送消息:使用
DatagramSocket
来创建一个用于发送数据的 UDP 套接字。通过DatagramPacket
将要发送的数据、目标 IP 地址和端口号封装成数据报,然后使用send
方法发送数据。 -
接收消息:同样使用
DatagramSocket
来创建一个 UDP 套接字,但需要绑定到一个特定的端口,用于监听传入的数据报。利用DatagramPacket
创建一个数据包作为接收缓冲区,然后调用receive
方法接收数据。 -
区别:发送方不需要指定端口,可以使用任意可用端口发送数据。而接收方则必须绑定到一个特定的端口,以便监听和接收数据报。
入门例子
发送端
public class UdpClient {
public static void main(String[] args) throws Exception {
// 创建一个 UDP 套接字
DatagramSocket socket = new DatagramSocket();
// 要发送的数据
byte[] data = "hello".getBytes();
// 创建一个数据包,包含数据、数据长度、目标 IP 地址和端口号
DatagramPacket packet = new DatagramPacket(
data,
data.length,
InetAddress.getByName("127.0.0.1"),
10010
);
// 发送数据包
socket.send(packet);
System.out.println("消息已发送~~~");
// 关闭套接字
socket.close();
}
}
接收方
public class UdpServer {
public static void main(String[] args) throws Exception {
System.out.println("服务端启动~~~");
// 创建一个 UDP 套接字,并绑定到指定端口(10010)
DatagramSocket socket = new DatagramSocket(10010);
// 用于接收数据的字节数组
byte[] buffer = new byte[1024];
// 创建一个数据包,用于接收数据
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
// 等待接收数据(阻塞调用)
socket.receive(packet);
// 从数据包中提取数据
byte[] data = packet.getData();
int length = packet.getLength();
String receivedMessage = new String(data, 0, length); // 根据实际长度构建字符串
System.out.println("收到数据: " + receivedMessage);
socket.close();
}
}
实时通信和多发多收
发送端
public class UdpClient {
public static void main(String[] args) {
// 创建一个 UDP 套接字
try (DatagramSocket socket = new DatagramSocket();
Scanner scanner = new Scanner(System.in)) {
System.out.println("客户端启动,输入消息并按回车发送,输入 'exit' 退出:");
while (true) {
String message = scanner.nextLine();
if ("exit".equalsIgnoreCase(message)) {
System.out.println("客户端退出");
break;
}
byte[] data = message.getBytes();
// 创建数据包,包含数据、目标 IP 地址和端口号
DatagramPacket packet = new DatagramPacket(
data,
data.length,
InetAddress.getByName("127.0.0.1"),
10010
);
socket.send(packet);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
接收方
public class UdpServer {
public static void main(String[] args) {
System.out.println("服务端启动,监听端口 10010");
// 创建并绑定一个 UDP 套接字到端口 10010
try (DatagramSocket socket = new DatagramSocket(10010)) {
while (true) {
// 用于接收数据的字节数组
byte[] buffer = new byte[1024];
// 创建数据包用于接收数据
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
// 接收数据包(阻塞调用)
socket.receive(packet);
// 从数据包中提取数据
String receivedMessage = new String(packet.getData(), 0, packet.getLength());
System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) +"收到消息: " + receivedMessage);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
多发多收改一改就出来了
注意:UDP通信的形式
- 单播:单台主机与单台主机之间的通信。
- 广播:当前主机与所在网络中的所有主机通信。
- 组播:当前主机与选定的一组主机的通信。
TCP通信
TCP通信中的核心类和数据流
在 Java 中,TCP 通信涉及两个主要的类:Socket
和 ServerSocket
。
1. 代表客户端的类:Socket
- 用途:
Socket
类用于客户端与服务器端进行通信。它提供了流式 I/O 操作的功能,使客户端能够通过网络发送和接收数据。 - 主要方法:
getOutputStream()
:获取一个OutputStream
对象,用于向服务器发送数据。getInputStream()
:获取一个InputStream
对象,用于从服务器接收数据。
- 创建实例:客户端通过
new Socket(String host, int port)
创建连接到指定 IP 地址和端口的套接字实例。
2. 代表服务端的类:ServerSocket
- 用途:
ServerSocket
类用于服务器端监听并接受来自客户端的连接请求。它用于在指定端口上等待客户端的连接,并为每个连接创建一个新的Socket
对象。 - 主要方法:
accept()
:接受来自客户端的连接请求,返回一个新的Socket
实例,用于与客户端通信。
- 创建实例:服务器端通过
new ServerSocket(int port)
创建一个在指定端口上监听连接的套接字实例。
Java 实现 TCP 通信例子
客户端
public class TcpClient {
public static void main(String[] args) {
System.out.println("客户端启动,连接到服务器...");
try (Socket socket = new Socket("127.0.0.1", 10010);
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
Scanner scanner = new Scanner(System.in)) {
while (true) {
System.out.print("输入消息 (输入 'exit' 退出): ");
String message = scanner.nextLine();
if ("exit".equalsIgnoreCase(message)) {
System.out.println("客户端退出");
break;
}
// 发送消息到服务器
os.write(message.getBytes());
os.flush();
// 接收服务器的响应
byte[] bytes = new byte[1024];
int len = is.read(bytes);
if (len != -1) {
String response = new String(bytes, 0, len);
System.out.println("服务端返回数据: " + response);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务端
public class TcpServer {
public static void main(String[] args) {
System.out.println("服务器启动,等待客户端连接...");
try (ServerSocket server = new ServerSocket(10010)) {
while (true) {
// 接受客户端连接
try (Socket socket = server.accept()) {
System.out.println("客户端已连接:" + socket.getInetAddress());
// 读取客户端发送的数据
try (InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream()) {
byte[] bytes = new byte[1024];
int len;
while ((len = is.read(bytes)) != -1) {
String receivedMessage = new String(bytes, 0, len);
System.out.println("接收到客户端数据: " + receivedMessage);
// 发送响应到客户端
String response = "服务端接收成功";
os.write(response.getBytes());
os.flush(); // 确保数据被及时发送
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Socket socket = server.accept();
用于接受来自客户端的连接请求,并返回一个新的 Socket 实例,用于与客户端进行通信。accept() 方法是一个阻塞调用
,这意味着服务器在调用此方法时会等待,直到有客户端尝试连接。如果没有客户端连接请求,服务器会在这里暂停执行,直到一个连接请求到达。
总结
- 客户端 (
Socket
) 用于创建连接并进行数据发送和接收。 - 服务端 (
ServerSocket
) 用于监听端口并接受客户端连接。 OutputStream
和InputStream
用于在 TCP 连接中发送和接收数据。
在实际应用中,确保在发送数据后调用 flush()
方法,以确保数据及时发送,并在接收数据时正确处理流的关闭和异常情况。
❤觉得有用的可以留个关注~~❤