UDP协议:
????? 基于TCP协议可以建立稳定连接的点对点的通信。这种通信方式实时、快速、安全性高,但是很占用系统的资源。
? ? ??在网络传输方式上,还有另一种基于UDP协议的通信方式,称为数据报通信方式。在这种方式中,每个数据发送单元被统一封装成数据报包的方式,发送方将数据报包发送到网络中,数据报包在网络中去寻找它的目的地。
UDP通讯的实现:
? DatagramSocket:用于发送或接收数据报包
? ? ? 当服务器要向客户端发送数据时,需要在服务器端产生一个DatagramSocket对象,在客户端产生一个DatagramSocket对象。服务器端的DatagramSocket将DatagramPacket发送到网络上,然后被客户端的DatagramSocket接收。
? ? ??DatagramSocket有两种常用的构造函数。一种是无需任何参数的,常用于客户端;另一种需要指定端口,常用于服务器端。如下所示:
? ? ??DatagramSocket() :构造数据报套接字并将其绑定到本地主机上任何可用的端口。
? ? ??DatagramSocket(int port) :创建数据报套接字并将其绑定到本地主机上的指定端口。
常用方法:
? ? ? 1.send(DatagramPacket p) :从此套接字发送数据报包。
? ? ? 2.receive(DatagramPacket p) :从此套接字接收数据报包。
? ? ? 3.close() :关闭此数据报套接字。
? DatagramPacket:数据容器(封包)的作用
? ? ??此类表示数据报包。 数据报包用来实现封包的功能。
常用方法:
? ? ? 1.DatagramPacket(byte[] buf, int length) :构造数据报包,用来接收长度为 length 的数据包。
? ? ? 2.DatagramPacket(byte[] buf, setOff,InerSocketAdress) :构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
? ? ? 3.getAddress() :获取发送或接收方计算机的IP地址,此数据报将要发往该机器或者是从该机器接收到的。
? ? ? 4.getData() :获取发送或接收的数据。
????? 5.getLength() :获取接收数据的大小。
UDP单向通讯:
客户端:
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
/*
发送端
1、使用DatagramSocket 指定端口,创建发送端
2、准备数据 一定转成字节数组
3、将数据封装程 DatagramPacket包裹,需指定目的地(IP+端口)
4、发送包裹 send(DatagramPacket p)
5、释放资源
*/
public class UdpClient {
public static void main(String[] args) throws Exception {
System.out.println("发送方启动中......");
//1、使用DatagramSocket 指定端口,创建发送端
DatagramSocket client = new DatagramSocket(8888);
//2、准备数据 一定转成字节数组
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String str = "0";
while(!str.equals("")){
str = reader.readLine();
//3、将数据封装程 DatagramPacket包裹,需指定目的地(IP+端口)
byte[] data = str.getBytes(StandardCharsets.UTF_8);
DatagramPacket packet = new DatagramPacket(data,0,data.length,
new InetSocketAddress("localhost",9999));
//4、发送包裹 send(DatagramPacket p)
client.send(packet);
}
//5、释放资源
client.close();
}
}
服务端:
import java.net.*;
/*
接收端
1、使用DatagramSocket 指定端口,创建接收端
2、准备容器,封装成DatagramPacket包裹
3、阻塞式接收包裹 receive(DatagramPacket p)
4、分析数据:byte[] getData();int getLength()。
5、释放资源
*/
public class UdpServer {
public static void main(String[] args) throws Exception{
System.out.println("接收方启动中......");
//1、使用DatagramSocket 指定端口,创建接受端
DatagramSocket server = new DatagramSocket(9999);
//2、准备容器,封装成DatagramPacket包裹
byte[] container = new byte[1024*60];
DatagramPacket packet = new DatagramPacket(container,0,container.length);
//3、阻塞式接收包裹 receive(DatagramPacket p)
server.receive(packet);
//4、分析数据
byte[] data = packet.getData();// container也行
int len = packet.getLength();// len为数据实际大小,data.length=container.length
String str = new String(data,0,len);
while(!str.equals("")){
System.out.println(str);
server.receive(packet);
data = packet.getData();
len = packet.getLength();
str = new String(data,0,len);
}
//5、释放资源
server.close();
}
}
?注:通过字节数组流ByteArrayInputStream、ByteArrayOutputStream与数据流DataInputStream、DataOutputStream联合使用可以传递基本数据类型。
UDP双向通讯:
客户端线程:
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
public class TalkSend implements Runnable {
private DatagramSocket client;
private String toIP;
private int toPort;
public TalkSend(int port,String toIP,int toPort) throws Exception {
client = new DatagramSocket(port);
this.toIP = toIP;
this.toPort = toPort;
}
@Override
public void run() {
//1、使用DatagramSocket指定端口client为发送端
//2、准备数据 一定转成字节数组
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String str = "null";
while(!str.equals("")){
try {
str = reader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
//3、将数据封装程 DatagramPacket包裹,需指定目的地(IP+端口)
byte[] data = str.getBytes(StandardCharsets.UTF_8);
DatagramPacket packet = new DatagramPacket(data,0,data.length,
new InetSocketAddress(toIP,toPort));
//4、发送包裹 send(DatagramPacket p)
try {
client.send(packet);
} catch (IOException e) {
e.printStackTrace();
}
}
//5、释放资源
client.close();
}
}
服务端线程:
import java.io.IOException;
import java.net.*;
public class TalkReceive implements Runnable {
private DatagramSocket server;
public TalkReceive(int port) throws SocketException {
server = new DatagramSocket(port);
}
@Override
public void run() {
//1、使用DatagramSocket指定端口server为接受端
//2、准备容器,封装成DatagramPacket包裹
byte[] container = new byte[1024*60];
DatagramPacket packet = new DatagramPacket(container,0,container.length);
//3、阻塞式接收包裹 receive(DatagramPacket p)
try {
server.receive(packet);
} catch (IOException e) {
e.printStackTrace();
}
//4、分析数据
byte[] data = packet.getData();// container也行
int len = packet.getLength();// len为数据实际大小,data.length=container.length
String str = new String(data,0,len);
while(!str.equals("")){
System.out.println(Thread.currentThread().getName()+":"+str);
try {
server.receive(packet);
} catch (IOException e) {
e.printStackTrace();
}
data = packet.getData();
len = packet.getLength();
str = new String(data,0,len);
}
//5、释放资源
server.close();
}
}
双向通讯的多线程实现:
public class Talker1 {
public static void main(String[] args) throws Exception {
new Thread(new TalkSend(8888,"localhost",9999),"Tom").start();
new Thread(new TalkReceive(5555),"Jerry").start();
}
}
public class Talker2 {
public static void main(String[] args) throws Exception {
new Thread(new TalkReceive(9999),"Tom").start();
new Thread(new TalkSend(6666,"localhost",5555),"Jerry").start();
}
}
执行结果:
|