UDP通信,个人的理解就是一个人拿盘子装好东西扔出去,另外一个人拿盘子接收,且发送端不管接收端有没有收到的一种通信方式,不安全但速度快。
首先要实现网络通信,基本的几个要素
IP地址:设备在网络中的地址,是唯一的标识
端口:应用程序在设备中的唯一标识
协议:数据在网络中传输的规则,常见的协议有UDP和TCP
UDP简介:
UDP是一种无连接,不可靠传输的协议
将数据源IP,目的地IP和端口封装成数据包,不需要建立连接
每个数据包大小限制在64kb内
发送不管对方是否准备好,接收方收到也不确认,所以是不可靠的
可以广播发送,发送数据结束时无需释放资源,开销小,速度快
UDP协议通信场景:语言通话,视频会话
UDP协议通信的过程大致是将发送端的IP、端口、数据封装成数据包,再发送给接收端。InetAddress类可以获取IP对象
// 1.获取本机地址对象
InetAddress ip1 = InetAddress.getLocalHost();
System.out.println(ip1.getHostName()); // 输出本机名称(网址)
System.out.println(ip1.getHostAddress()); // 服务器IP
// 2.获取域名ip对象
InetAddress ip2 = InetAddress.getByName("www.baidu.com");
System.out.println(ip2.getHostName()); // 网址
System.out.println(ip2.getHostAddress()); // 服务器ip
// 3.获取公网IP对象
InetAddress ip3 = InetAddress.getByName("112.80.248.76");
System.out.println(ip3.getHostName());
System.out.println(ip3.getHostAddress());
java中的DatagramPacket类可以作为发送端或接收端的数据包对象(盘子),其构造方法有很多种;而发送或接收的对象(人),java中可以用DatagramSocket类来创建实例,调用send()方法发送数据包(盘子),调用receive()方法接收数据包(盘子)。下面是一个以本机当作服务器通信的例子。
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
/**
* 客户端
*/
public class ClientDemo1 {
public static void main(String[] args) {
System.out.println("-----客户端启动-----");
// 1.创建发送端对象,发送端自带默认的端口号
DatagramSocket socket;
try {
socket = new DatagramSocket(6666);
} catch (SocketException e) {
throw new RuntimeException(e);
}
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("请说:");
String msg = sc.nextLine();
if ("exit".equals(msg)) {
System.out.println("离线成功");
socket.close();
break;
}
// 2.创建一个数据包对象封装数据
byte[] buffer = msg.getBytes();
InetAddress myIp;
try {
myIp = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
DatagramPacket packet = new DatagramPacket(
buffer, // 封装要发送的数据
buffer.length, // 发送数据的大小
myIp, // 服务端的IP地址
8888); // 服务端的端口号
// 3.数据发送出去
try {
socket.send(packet);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class ServerDemo2 {
public static void main(String[] args) {
System.out.println("-----服务端启动-----");
// 1.创建接收端对象,注册端口(人)
DatagramSocket socket;
try {
socket = new DatagramSocket(8888);
} catch (SocketException e) {
throw new RuntimeException(e);
}
// 2.创建一个数据包对象接收数据(盘子)
byte[] buffer = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(
buffer,
buffer.length);
while(true){
// 3.等待接收数据
try {
socket.receive(packet);
} catch (IOException e) {
throw new RuntimeException(e);
}
// 4.取出数据即可
int len = packet.getLength();
String rs = new String(buffer, 0, len); // 读取多少导出多少
System.out.println("收到了" + rs);
// 获取发送端的ip和端口
String ip = packet.getSocketAddress().toString();
System.out.println("对方地址" + ip);
int port = packet.getPort();
System.out.println("对方端口" + port);
}
}
}
除了以上简单的用法,UDP协议还可以实现广播与组播
广播:
发送端发送的数据包的目的地写的是广播地址,且指定端口(255.255.255.255, 9999)
本机所在网段的其他主机的程序只要匹配端口成功即就可以收到消息了(9999)
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
/**
* 客户端,UDP广播
*/
public class ClientDemo {
public static void main(String[] args) {
System.out.println("-----客户端启动-----");
// 1.创建发送端对象,发送端自带默认的端口号
DatagramSocket socket;
try {
socket = new DatagramSocket(6666);
} catch (SocketException e) {
throw new RuntimeException(e);
}
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("请说:");
String msg = sc.nextLine();
if ("exit".equals(msg)) {
System.out.println("离线成功");
socket.close();
break;
}
// 2.创建一个数据包对象封装数据
byte[] buffer = msg.getBytes();
InetAddress myIp;
try {
myIp = InetAddress.getByName("255.255.255.255");
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
DatagramPacket packet = new DatagramPacket(
buffer, // 封装要发送的数据
buffer.length, // 发送数据的大小
myIp, // 服务端的IP地址
9999); // 服务端的端口号
// 3.数据发送出去
try {
socket.send(packet);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class ServerDemo {
public static void main(String[] args) {
System.out.println("-----服务端启动-----");
// 1.创建接收端对象,注册端口(人)
DatagramSocket socket;
try {
socket = new DatagramSocket(9999);
} catch (SocketException e) {
throw new RuntimeException(e);
}
// 2.创建一个数据包对象接收数据(盘子)
byte[] buffer = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(
buffer,
buffer.length);
while(true){
// 3.等待接收数据
try {
socket.receive(packet);
} catch (IOException e) {
throw new RuntimeException(e);
}
// 4.取出数据即可
int len = packet.getLength();
String rs = new String(buffer, 0, len); // 读取多少导出多少
System.out.println("收到了" + rs);
// 获取发送端的ip和端口
String ip = packet.getSocketAddress().toString();
System.out.println("对方地址" + ip);
int port = packet.getPort();
System.out.println("对方端口" + port);
}
}
}
组播
* 发送端的数据包的目的地是组播IP(例如224.0.1.1 端口9999)
* 接收端必须绑定该组播IP(224.0.1.1),端口还要对应发送端的目的端口9999,这样即可接收该组播消息
* DatagramSocket的子类MulticastSocket可以在接收端绑定组播IP
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
/**
* 客户端,UDP组播
*/
public class ClientDemo {
public static void main(String[] args) {
System.out.println("-----客户端启动-----");
// 1.创建发送端对象,发送端自带默认的端口号
DatagramSocket socket;
try {
socket = new DatagramSocket(6666);
} catch (SocketException e) {
throw new RuntimeException(e);
}
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("请说:");
String msg = sc.nextLine();
if ("exit".equals(msg)) {
System.out.println("离线成功");
socket.close();
break;
}
// 2.创建一个数据包对象封装数据
byte[] buffer = msg.getBytes();
InetAddress myIp;
try {
myIp = InetAddress.getByName("224.0.1.1");
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
DatagramPacket packet = new DatagramPacket(
buffer, // 封装要发送的数据
buffer.length, // 发送数据的大小
myIp, // 服务端的IP地址
9999); // 服务端的端口号
// 3.数据发送出去
try {
socket.send(packet);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
import java.io.IOException;
import java.net.*;
public class ServerDemo {
public static void main(String[] args) {
System.out.println("-----服务端启动-----");
// 1.创建接收端对象,注册端口(人),组播用MulticastSocket
MulticastSocket socket;
try {
socket = new MulticastSocket(9999); // 此方法已过时
} catch (IOException e) {
throw new RuntimeException(e);
}
// 把当前接收端加入到一个组播组中去,绑定对应的组播消息的组播IP
try {
socket.joinGroup(InetAddress.getByName("224.0.1.1"));
} catch (IOException e) {
throw new RuntimeException(e);
}
// 2.创建一个数据包对象接收数据(盘子)
byte[] buffer = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(
buffer,
buffer.length);
while (true) {
// 3.等待接收数据
try {
socket.receive(packet);
} catch (IOException e) {
throw new RuntimeException(e);
}
// 4.取出数据即可
int len = packet.getLength();
String rs = new String(buffer, 0, len); // 读取多少导出多少
System.out.println("收到了" + rs);
// 获取发送端的ip和端口
String ip = packet.getSocketAddress().toString();
System.out.println("对方地址" + ip);
int port = packet.getPort();
System.out.println("对方端口" + port);
}
}
}