前言
UDP为用户数据报协议,在java中操纵UDP使用JDK中java.net包下的DatagramSocket和DatagramPacket类,可以方便的控制用户数据报文。DatagramPacket类将数据字节填充到UDP包中,这称为数据报。
DatagramSocket用来发送这个包。如果接受数据,可以从DatagramSocket中接受一个
DatagramPack对象,然后从该包中读取数据的内容。UDP是面向无连接的单工通信,它速度快
DatagramSocket类
构造函数:
DatagramSocket()
创建实例,通常用于客户端编程,他并没有特定的监听端口,仅仅使用一个临时的。
DatagramSocket(int port)
创建实例,并固定监听Port端口的报文。
DatagramSocket(int port, InetAddress laddr)
这是个非常有用的构建器,当一台机器拥有多于一个IP地址的时候,由它创建的实例仅仅接收来自LocalAddr的报文。
DatagramSocket(SocketAddress bindaddr)
bindaddr对象中指定了端口和地址。
常用函数:
receive(DatagramPacket p)
接收数据报文到p中。receive方法是阻塞的,如果没有接收到数据报包的话就会阻塞在哪里。
send(DatagramPacket p)
发送报文p到目的地。
setSoTimeout(int timeout)
设置超时时间,单位为毫秒。
close()
关闭DatagramSocket。在应用程序退出的时候,通常会主动的释放资源,关闭Socket,但是由于异常的退出可能造成资源无法回收。所以应该在程序完成的时候,主动使用此方法关闭Socket,或在捕获到异常后关闭Socket。
DatagramPacket类
DatagramPacket类用于处理报文,将字节数组、目标地址、目标端口等数据包装成报文或者将报文拆卸成字节数组。
构造函数:
DatagramPacket(byte[] buf, int length, InetAddress addr, int port)
从buf字节数组中取出offset开始的、length长的数据创建数据对象,目标地址是addr,目标端口是port。
DatagramPacket(byte buf[], int offset, int length, SocketAddress address)
从buf字节数组中取出offset开始的、length长的数据创建数据对象,目标地址是address
常用函数:
getData() byte[]
从实例中取得报文中的字节数组编码。
setData(byte[] buf, int offset, int length)
设置数据报包中的数据内容
案例
接收端
package TCP通信流程.UDP案例;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;
public class TestReceive {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.println("等待发送端。。。。。发送数据");
try {
//指定接受端端口号,供发送端发送数据
DatagramSocket datagramSocket = new DatagramSocket(9999);
byte[] buf = new byte[1024];
//指定数据包接收数据
DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);
//从数据包用getLength获取数据实际大小
int length=datagramPacket.getLength();
//接受数据
datagramSocket.receive(datagramPacket);//将数据接收后用DatagramPacket数据包储存
System.out.println("接收到发送端的数据");
//打印输出将数据包中的字节数组转换成字符串,按照实际的大小去转换
java.lang.String data=new java.lang.String(buf,0,length);
System.out.println("发送端发出的信息:"+data);
//回写给发送端
//String data1 = "收到,谢谢";
System.out.println("回写给发送端:");
String data1=scanner.nextLine();
//字符串数据转换
byte[] bytes = data1.getBytes();
//指定要连接那个接收端 指定IP 指定端口号 数据包类
DatagramPacket datagramPacket1 = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("localhost"), 8888);
//将准备好的数据包发送,到我们接受端,只需要调用一个方法就可以,(必须基于一个同一个通道)send方法
datagramSocket.send(datagramPacket1);
//关闭
datagramSocket.close();
} catch (Exception E) {
System.out.println(E);
}
}
}
发送端
package TCP通信流程.UDP案例;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Testsend {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
try {
//发送端和接受端进行通信的socket,
DatagramSocket datagramSocket = new DatagramSocket(8888);//接受端回写数据包时所需端口号
//一字符串形式存在
//String data = "我爱学习";
System.out.println("请输入要发送的内容:");
String data=scanner.nextLine();
//字符串数据转换
byte[] bytes = data.getBytes();
//指定要连接那个接收端 指定IP 指定端口号 数据包类
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("localhost"), 9999);
//将准备好的数据包发送,到我们接受端,只需要调用一个方法就可以,(必须基于一个同一个通道)send方法
datagramSocket.send(datagramPacket);
//接收回写数据
byte[] buf = new byte[1024];
//指定数据包接收数据
DatagramPacket datagramPacket1 = new DatagramPacket(buf, buf.length);
//从数据包用getLength获取数据实际大小
int length=datagramPacket1.getLength();
//接受数据
datagramSocket.receive(datagramPacket1);
System.out.println("接收到接收端回写的数据");
//打印输出将数据包中的字节数组转换成字符串,按照实际的大小去转换
java.lang.String data1=new java.lang.String(buf,0,length);
System.out.println("接收端回写的内容:"+data1);
//关闭
datagramSocket.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
UDP丢包案例
在传输过程中会发生数据不完整缺失,这就是我们所讲的丢包
接受端
package TCP通信流程.UDP丢包;
import java.io.FileOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class TestReceive {
public static void main(String[] args) {
try {
//数据的再次写入,利用本地字节输出流去完成
FileOutputStream fileOutputStream =new FileOutputStream("");//这里做好是一个大点的文件或视频
//指定接收端端口,用于发送端发送数据
DatagramSocket datagramSocket=new DatagramSocket(9999);
byte[]bytes=new byte[1024];
while (true) {//死循环,会随着发送结束而结束
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
//数据包中实际数据包大小
int length = datagramPacket.getLength();
//接受发送端发送的数据
datagramSocket.receive(datagramPacket);
//调用write方法写
fileOutputStream.write(bytes, 0, length);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
发送端
package TCP通信流程.UDP丢包;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class TestSend {
public static void main(String[] args) {
//本地读取
try {
//用于和接受端通信的socker
DatagramSocket socket=new DatagramSocket();
//本地直接输入流,读取本地文件,用于发送
FileInputStream fileInputStream=new FileInputStream("D://");
//构建字节数组用于读取
byte[]bytes=new byte[100];//每次以100字节读取
int len=0;
//边读边写
while ((len=fileInputStream.read(bytes)) != -1) {
//以数据包的形式发送
DatagramPacket datagramPacket=new DatagramPacket(bytes,bytes.length, InetAddress.getByName("localhost"),9999);
socket.send(datagramPacket);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
解决方案
优化:
1.数据发慢一点
2.接收端做数据的回写记录,发送OK,才可以进行下一次的发送
优化一
1.数据发慢一点
接收端
package TCP通信流程.UDP丢包优化;
import java.io.FileOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class TestReceive {
public static void main(String[] args) {
try {
//数据的再次写入,利用本地字节输出流去完成
FileOutputStream fileOutputStream =new FileOutputStream("");
//指定接收端端口,用于发送端发送数据
DatagramSocket datagramSocket=new DatagramSocket(9999);
byte[]bytes=new byte[1024];
while (true) {//死循环,会随着发送结束而结束
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
//数据包中实际数据包大小
int length = datagramPacket.getLength();
//接受发送端发送的数据
datagramSocket.receive(datagramPacket);
//调用write方法写
fileOutputStream.write(bytes, 0, length);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
发送端
package TCP通信流程.UDP丢包优化;
import java.io.FileInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/
* 优化一
* 数据发慢一些
*
* 缺点 是发送太慢
*/
public class TestSend {
public static void main(String[] args) {
//本地读取
try {
//用于和接受端通信的socker
DatagramSocket socket=new DatagramSocket();
//本地直接输入流,读取本地文件,用于发送
FileInputStream fileInputStream=new FileInputStream("D://");
//构建字节数组用于读取
byte[]bytes=new byte[100];//每次以100字节读取
int len=0;
//边读边写
while ((len=fileInputStream.read(bytes)) != -1) {
//利用线程sleep,让数据发慢一点
Thread.sleep(1);
//以数据包的形式发送
DatagramPacket datagramPacket=new DatagramPacket(bytes,bytes.length, InetAddress.getByName("localhost"),9999);
socket.send(datagramPacket);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
优化二
接收端
package TCP通信流程.UDP丢包优化二;
import java.io.FileOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/
* 接收端
* 缺点:
* 会发生丢包现象
* 优化
* 1.数据发慢一点
* 2.接收端做数据的回写记录,发送OK,才可以进行下一次的发送
*/
public class TestReceive {
public static void main(String[] args) {
try {
//数据的再次写入,利用本地字节输出流去完成
FileOutputStream fileOutputStream =new FileOutputStream("");
//指定接收端端口,用于发送端发送数据
DatagramSocket datagramSocket=new DatagramSocket(9999);
byte[]bytes=new byte[1024];
int count=0;
while (true) {//死循环,会随着发送结束而结束
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
//数据包中实际数据包大小
int length = datagramPacket.getLength();
//接受发送端发送的数据
datagramSocket.receive(datagramPacket);
//调用write方法写
fileOutputStream.write(bytes, 0, length);
count++;
System.out.println("接受的数据包:"+count);
//接收端发送数据
DatagramPacket datagramPacket1=new DatagramPacket("ok".getBytes(),2, InetAddress.getByName("localhost"),8888);
//调用socker发送数据
datagramSocket.send(datagramPacket1);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
发送端
package TCP通信流程.UDP丢包优化二;
import java.io.FileInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
*发送端
*
* 优化二:
2.接收端做数据的回写记录,发送OK,才可以进行下一次的发送
*/
public class TestSend {
public static void main(String[] args) {
//本地读取
try {
//用于和接受端通信的socker
DatagramSocket socket=new DatagramSocket(8888);//接受端回写数据包时所需端口号
//本地直接输入流,读取本地文件,用于发送
FileInputStream fileInputStream=new FileInputStream("D://");
//构建字节数组用于读取
byte[]bytes=new byte[100];//每次以100字节读取
int len=0;
int count=0;
//边读边写
while ((len=fileInputStream.read(bytes)) != -1) {
//以数据包的形式发送
DatagramPacket datagramPacket=new DatagramPacket(bytes,bytes.length, InetAddress.getByName("localhost"),9999);
socket.send(datagramPacket);
count++;
//以数据包的形式接受
byte[]bytes1=new byte[2];
DatagramPacket datagramPacket1 = new DatagramPacket(bytes1, bytes1.length);
//接受回写数据
socket.receive(datagramPacket1);
String date=new String(bytes1);
System.out.println(date);
//是否是ok
if (date.equals("ok")) {
continue;
} else {
}
}
System.out.println("发送端实际数据大小:"+count);
} catch (Exception e) {
e.printStackTrace();
}
}
}
URl类
URL 是统一资源定位符(Uniform Resource Locator)的简称,它表示 Internet 上某一资源的地址。通过 URL
用户可以访问各种网络资源,比如常见的 WWW 以及 FTP 站点。浏览器可以通过解析给定的 URL 在网络上查找相应的文件或其他资源。
案例
简单获取百度首页html
package TCP通信流程.URL;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
/**
*
* 功能描述:
* 基于URL统一资源定位器,去指定百度的首页,然后获取百度首页内容写到本地,以此来体验URL的作用
* 1.通过URL指定域名资源
* 2.通过openConnection()打开资源连接URLConnection 的连接conn
* 3.通过URLConnection对象conn去常见字节输入流InputStre am的对象is
* 4.使用is调用read()方法去读取百度首页的数据
* 5.创建本地的字节输出流F ile0utStream对象fos
* 6.使用fos对象将读到的数据写到本地
* 7.关闭流
*
*/
public class Connection {
public static void main(String[] args) {
try {
//1.通过URL指定域名资源
URL url=new URL("http://www.baidu.com");
//2.通过openConnection()打开资源连接URLConnection 的连接conn
URLConnection urlConnection = url.openConnection();
//3.通过URLConnection对象conn去常见字节输入流InputStream的对象is
InputStream is = urlConnection.getInputStream();
byte[]bytes=new byte[100];
int count=0;
//5.创建本地的字节输出流F ile0utStream对象fos
FileOutputStream fileOutputStream=new FileOutputStream("D://baidu.html");
//4.使用is调用read()方法去读取百度首页的数据
while ((count=is.read(bytes,0,10))!=-1){
fileOutputStream.write(bytes,0,count);
}
//7.关闭流
is.close();
fileOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}