UDP通信跟TCP通信的最大区别在于 他不用创建连接
就像打电话和发短信的区别。
不可靠、无连接、面向报文
面向数据报文导致的一个后果:
由于底层(物理层+网络层))都对一次发送的数据有大小限制。如果强行发送大于限制的数据,就会出现数据被截断。
全双工:同一个信道是双向的。
UDP协议的最适用场景
对实时性要求较高,对可靠性要求较低的场景
实时聊天(语音、视频聊天)
UDP支持广播。如果有广播需求,也可以考虑用UDP。
下面用模拟一下udp场景
接收端
public class ChatServer {
public static void main(String[] args) throws Exception {
//开放端口
DatagramSocket socket = new DatagramSocket(9998);
//定义bytes去开辟空间接收数据
byte[] bytes = new byte[9];
//接收数据包
DatagramPacket packet = new DatagramPacket(bytes,0,bytes.length);
//阻塞进程 等待接收
socket.receive(packet);
for (byte aByte : bytes) {
System.out.println("接收完了"+aByte);
}
System.out.println(packet.getAddress().getHostAddress());
System.out.println(new String(packet.getData(),0,packet.getLength()));
}
}
发送端
public class ChatUser {
public static void main(String[] args) throws Exception {
//建立一个数据包连接
DatagramSocket socket = new DatagramSocket(9997);
//创建一个数据包
String msg = "李佳琪";
byte[] msgByteArray = msg.getBytes();
InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
//参数解释 数据包 数据的起始位置 ip 端口
DatagramPacket datagramPacket = new DatagramPacket(msgByteArray,0,msgByteArray.length,inetAddress,9998);
//发送数据包
socket.send(datagramPacket);
//关闭连接
socket.close();
}
}
循环发送和接收
循环发送
public class ChatTwo {
public static void main(String[] args) throws Exception {
//创建自己的服务
DatagramSocket datagramSocket = new DatagramSocket(8888);
while (true){
//控制写入数据
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String data = reader.readLine();
//转换为字节数组
byte[] bytes = data.getBytes();
//创建数据包
DatagramPacket datagramPacket = new DatagramPacket(bytes,0,bytes.length, InetAddress.getByName("localhost"),666);
//发送数据包
datagramSocket.send(datagramPacket);
if ("bye".equals(data)){
System.out.println("退出聊天");
break;
}
}
datagramSocket.close();
}
}
循环接收
public class ChatOne {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(666);
while(true){
//接收包裹
byte[] bytes = new byte[1024];
//开启数据包空间
DatagramPacket packet = new DatagramPacket(bytes,0,bytes.length);
//接收数据包
socket.receive(packet);
//获取数据并转换为string
byte[] data= packet.getData();
String receiveData = new String(data,0,packet.getLength());
//输出内容
System.out.println(receiveData);
if ("bye".equals(receiveData)){
System.out.println("退出聊天");
break;
}
}
}
}
下面实现正常的聊天功能
发送消息线程类
/**
* @author : LeeGaki
* @date : 2022/6/5 19:47
* 面向面试编程 --> 李佳琪
*/
public class ChatSend implements Runnable{
/**
* 创建自己的连接
* 从控制台接收
* 自己的端口
* 发到的ip和端口
*/
DatagramSocket datagramSocket = null;
BufferedReader bufferedReader = null;
private int fromPort;
private String toIp;
private int toPort;
private String myName;
private String toName;
/**
* 构造方法
* 创建从控制台接收
* @param fromPort
* @param toIp
* @param toPort
*/
public ChatSend(int fromPort, String toIp, int toPort,String myName,String toName) {
this.fromPort = fromPort;
this.toIp = toIp;
this.toPort = toPort;
this.myName = myName;
this.toName = toName;
try {
bufferedReader = new BufferedReader(new InputStreamReader(System.in));
datagramSocket = new DatagramSocket(fromPort);
} catch (SocketException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
System.out.println("您的身份是"+this.myName);
System.out.println("直接写入即可发送消息给"+toName);
while(true){
//发送控制台写入的数据
String data = bufferedReader.readLine();
byte [] bytes = data.getBytes();
DatagramPacket datagramPacket = new DatagramPacket(bytes,0,bytes.length, new InetSocketAddress(this.toIp,this.toPort));
datagramSocket.send(datagramPacket);
if ("bye".equals(data)){
break;
}
}
datagramSocket.close();
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
接收消息线程类
/**
* @author : LeeGaki
* @date : 2022/6/5 20:12
* 面向面试编程 --> 李佳琪
*/
public class ChatReceive implements Runnable{
DatagramSocket datagramSocket = null;
private String fromUser;
private int myPort;
public ChatReceive(String fromUser,int myPort){
this.fromUser = fromUser;
this.myPort = myPort;
try {
datagramSocket = new DatagramSocket(myPort);
} catch (SocketException e) {
e.printStackTrace();
}
}
public String getFromUser(){
return this.fromUser;
}
@Override
public void run() {
while (true){
byte [] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes,0,bytes.length);
try {
datagramSocket.receive(datagramPacket);
byte[] data = datagramPacket.getData();
String str = new String(data,0,datagramPacket.getLength());
System.out.println(this.fromUser+":"+str);
if ("bye".equals(str)){
System.out.println("回复bye确认拜拜");
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
datagramSocket.close();
}
}
实现类
/**
* @author : LeeGaki
* @date : 2022/6/5 20:25
* 面向面试编程 --> 李佳琪
*/
public class ChatStudent {
public static void main(String[] args) {
ChatReceive receiveUser = new ChatReceive("李佳琪", 7777);
ChatSend sendUser = new ChatSend(7776, "127.0.0.1", 7775, "郭佳帅", receiveUser.getFromUser());
new Thread(receiveUser).start();
new Thread(sendUser).start();
}
}
/**
* @author : LeeGaki
* @date : 2022/6/5 20:27
* 面向面试编程 --> 李佳琪
*/
public class ChatTeacher {
public static void main(String[] args) {
ChatReceive receiveUser = new ChatReceive("郭佳帅", 7775);
ChatSend sendUser = new ChatSend(7774, "127.0.0.1", 7777, "李佳琪", receiveUser.getFromUser());
new Thread(receiveUser).start();
new Thread(sendUser).start();
}
}