----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
Socket通信端点具备了,但是数据传输协议是不一样的。因此每一种数据传输协议都有自己特有创建Socket通信端点的方法。
UDP协议是面相无连接的协议并且数据的传输形式数据报包。与UDP传输协议本身相关的类就是DatagramSocket类。与UDP每次传输数据形式相关的类就是DatagramPacket类。
(1). DatagramPacket类
[1]. DatagramPacket类所在的位置
DatagramPacket位于java.net包中
[3]. DatagramPacket类的直接父类
DatagramSocket类的直接父类就是java.lang.Object类
[4]. DatagramPacket类的源码声明
public final class DatagramPacket {
//...
}
【注意】DatagramPacket类是一个不可以被继承的类。
[5]. DatagramSocket类的含义
此类是对UDP数据传输过程中的数据报 (Datagram) 包的封装
(2). DatagramPacket类的构造方法
java.net.DatagramPacket类在构造方法中涉及到的IP地址和端口号指的是数据报包被发送的目的地所在主机的IP地址和端口号
[1]. 分析DatagramPacket构造函数的基本参数
{1}. DatagramPacket是对UDP数据传输协议中数据的包装。
{2}. 一般通用的数据使用的数据类型都是byte[]类型。
{3}. 根据另一个规律:有数组,通常就会有指针和计数器(有时候也叫总长度)。
因此,参数类型就有可能是下面的几种:
{3}1. byte buf[], int length
{3}2. byte buf[], int offset, int length
{4}. 注意到数据一定是用户指定的,而不是系统能够自行获取的。所以DatagramPacket的构造方法一定没有空参数的重载形式。
{5}. 由于是Socket之间的数据对传。可能需要指定发送的IP+ 该IP上某端口的App
{5}1. 如果这个数据报包用于发送,此时目标地址必须明确,而不能通过内部生成,因此这里面IP地址和端口号一定是同时出现。
如果这个数据报包用于接收,则不用明确地址,因为Socket所在的本机就是目标,可以通过系统自动获得。
{5}和{3}进行结合,产生出常用的四种构造方法。
[2]. DatagramPacket四种常用的重载构造方法声明
用于UDP数据传输中的用于接收数据的数据报包对象
{1}. publicDatagramPacket(byte buf[],int length);
{2}. publicDatagramPacket(byte buf[],int offset,int length);
用于UDP数据传输中的用于发送数据的数据报包对象
{3}. public DatagramPacket(byte buf[], int length,InetAddress address,int port);
{4}. publicDatagramPacket(byte buf[],int offset,int length,InetAddress address,int port);
【规律】构造方法中凡是带有IP和PORT的DatagramPacket的数据报包都是用来发送的数据报包,否则都是用于接收的数据报包。
(1). DatagramPacket的JavaBean性质
[1]. DatagramPacket是一个不折不扣的JavaBean类,它的方法主要分成了对私有字段的Setter和Getter方法
[2]. DatagramSocket私有字段
{1}. 待发送数据对应的byte[]数组
byte[] buf;
{2}. 待发送数据对应的byte[]数组有效部分对应的起始指针
int offset;
{3}. 待发送数据对应的byte[]数组有效部分对应的总长度
int length;
int bufLength;
以我个人判断,现在两个属性的值是一样的
{3}1. 在setData(byte[] buf,int offset,int length)中
this.length = length;this.bufLength = length;
{3}2. 在setData(byte[] buf)中
this.length = buf.length;this.bufLength = buf.length;
{3}3. 在setLength(int length)中
this.bufLength =this.length;
{4}. 待发送数据应发送的目标主机的IP地址
InetAddress address;
{5}. 待发送数据应发送的目标主机上App的端口号
int port;
(2). DatagramPacket的Setter和Getter方法
[1]. 获取/设置目标主机的IP地址
getAddress()/setAddress(InetAddressiaddr)
[2]. 获取/设置目标主机的App的Port端口号
getPort()/setPort(int iport)
[3]. 获取/设置待发送的数据报包中的原始数据
getData()/setData(xxx)
setData有三种重载形式
setData(byte[] buf, int offset, int length); setData(int offset);
setData(int length)
[4]. 获取/设置待发送的数据报包中的原始数据的有效总长度
getLength()/setLength(int length);
[5]. 获取/设置待发送的数据报包中的原始数据的有效起始位置
getOffset()/setOffset(int offset);
(1). DatagramSocket类
[1]. DatagramSocket类所在的位置
DatagramSocket位于java.net包中
[3]. DatagramSocket类的直接父类
DatagramSocket类的直接父类就是java.lang.Object类
[4]. DatagramSocket类的含义和作用
{1}. DatagramSocket类中的单词Datagram就是UDP中的字母D
{2}. 为UDP协议传输数据需要的Socket通信端点进行了封装。
{3}. 此类表示的通信端点Socket用于发送和接收UDP数据传输过程中的数据报 (Datagram) 包
【注意】DatagramSocket既可以用于发送数据,又可以用于接收数据
(2). DatagramSocket类的构造方法
[1]. DatagramSocket和DatagramPacket构造方法中IP和Port参数的关系
{1}. java.net.DatagramPacket类在构造方法中涉及到的IP地址和端口号
指的是Socket通信端点将数据报包发送到的目的地所在主机的IP地址和端口号
{2}.java.net.DatagramSocket类在构造方法中涉及到的IP地址和端口号
指的是Socket通信端点本身所在主机的IP地址和端口号
{3}. DatagramSocket构造中指定的是数据的源,DatagramPacket构造中指定的是数据的目的地
[2]. 分析DatagramSocket构造函数的基本参数
【注意】DatagramSocket仅仅负责数据的发送和接收,而对数据的封装工作全部由DatagramPacket类的构造进行了封装。因此DatagramSocket仅仅负责从本机发出数据或者在本机接受数据。因此DatagramSocket的构造方法仅仅涉及本机IP和端口号的传参。由于Socket本身位于本机的App上面,因此就算不指定本机的IP或者端口,系统也会根据内部的参数自动获取到本机的IP或者App对象的端口号。因此,可以有空参数的构造函数。
因此,参数类型就有可能是下面的几种:
{1}. 空参数
{2}. int port
{3}. InetAddressladdr, int port
[2]. DatagramPacket四种常用的重载构造方法声明
[3]. 空参构造函数
{1}. 构造方法原型
public DatagramSocket() throwsSocketException;
{2}. 构造方法的说明
{2}1. [对端口的绑定]
构建了一个用于UDP通信的Socket端点并且将这个UDP通信端点Socket绑定到本地主机的任意可用端口。
{2}2. [对IP地址的绑定]
这个Socket将被绑定到由被系统内核选择的出来的IP地址,即通配符IP地址。
[4]. 仅指定端口的构造函数
{1}. 构造方法原型
public DatagramSocket(intport)throwsSocketException;
{2}. 构造方法的说明
{2}1. [对端口的绑定]
构建了一个用于UDP通信的Socket端点并且将这个UDP通信端点Socket绑定到本地主机的指定的端口port。
{2}2. [对IP地址的绑定]
这个Socket将被绑定到由被系统内核选择的出来的IP地址,即通配符IP地址。
[4]. 指定端口和IP地址的构造函数
{1}. 构造方法原型
public DatagramSocket(int port,InetAddress laddr)throws SocketException;
{2}. 构造方法的说明
{2}1. [对端口的绑定]
构建了一个用于UDP通信的Socket端点并且将这个UDP通信端点Socket绑定到本地主机的指定端口。
{2}2. [对IP地址的绑定]
这个Socket将被绑定到本机指定的IP地址。
[5]. [2]和[3]中两种重载方法的关系
public DatagramSocket(int port) throws SocketException {
this(port, null);
}
结论DatagramSocket(int port)是对DatagramSocket(int port,InetAddress laddr)的调用
(1). 发送数据报包
[1]. 方法原型
public voidsend(DatagramPacket p) throws IOException;
[2]. 输入参数
DatagramPacketp:要发送的数据报包
(2). 接收数据报包
[1]. 方法原型
public void receive(DatagramPacketp) throws IOException;
[2]. 输入参数
DatagramPacketp:接收从发送方发送的数据,并打包成DatagramPacket对象存放在这个参数中。
[3]. receive方法是一个阻塞式方法。程序中如果调用了这个方法,并且对应的接收端的Socket端点没有接收到数据报包,就会一直等待不动。直到这个接收
端的DatagramSocket接收到了数据报包,receive方法才会被执行完。这样整个程序就向下继续执行。
使用Socket就是记住使用流程,直接走流程即可
需求:通过UDP传输方式,将一段文字数据发送出去
(1). UDP发送端的操作流程
[1]. 建立UDPSocket服务,即建立Socket发送端点。
[2]. 提供数据并将数据封装到DatagramPacket中。
[3]. 通过UDP的Socket的发送功能将数据发送出去。
[4]. 关闭Socket。
因为网络通讯的最底层要走物理层,也就意味着底层的网卡资源被调用。所以关闭Socket就是在使用完底层资源之后对底层资源进行释放。
(2). UDP端发送数据代码示例
import java.net.*;
/*
需求:通过UDP传输方式,将一段文字数据发送出去
思路:
1.建立UDPSocket服务,即建立端点
2.提供数据,并将其封装到数据报包中
3.通过Socket服务的发送功能,将数据报发送出去
4.关闭资源
*/
class UdpSend{
public static void main(String[] args) throws Exception{
//1.创建UDP服务。通过DatagramSocket建立
DatagramSocketds =new DatagramSocket();
//2.确定数据并封装成数据包
byte[] buf ="UDP is coming...".getBytes();
DatagramPacketdp =new DatagramPacket(buf, buf.length, InetAddress.getByName("127.0.0.1"), 10000);
//3.通过Socket服务将已有数据通过send方法发送出去
ds.send(dp);
//4.关闭资源
ds.close();
}
}
需求:定义一个App用于接收通过UDP协议传输过来的数据
(1). UDP接收端的操作流程
[1]. 建立UDPSocket服务,即建立Socket接收端点。
[2].定义一个数据报包。因为要存储接收到通过UDP传输来的字节数据,并且接收到的数据有很多信息。如果自行提取会非常麻烦。因此直接封装成数据报包对象,调用该对象不同的方法从而获取接收到的数据报包中的信息。(直接利用DataPacket类的JavaBean的Getter方法获取各种信息)
[3]. 通过UDP接收端的Socket的receive方法将接收到的数据取出,并存入已定义好的数据报包对象中。
[4]. 关闭Socket资源。
【注意】在建立UDP接收服务的时候,通常会监听一个端口。
如何监听?在new DatagramSocket的时候,不能使用空参构造函数,应该使用至少含有一个端口号的构造函数:DatagramSocketds =new DatagramSocket(10000);
这个端口就是给网络应用程序的一个数字标识。用于标识发送来的哪些数据到这个端口的应用程序进行处理。
发送端可以使用空参构造函数。
(2). UDP端接收数据代码示例
import java.net.*;
class UdpRece{
public static void main(String[] args) throws Exception{
//1、创建udp Socket服务,建立端点
DatagramSocketds =new DatagramSocket(10000);
while(true){
//2、定义数据报包对象,用于接收发送过来的数据
byte[] buf =new byte[1024];
DatagramPacketdp =new DatagramPacket(buf, buf.length);
//3、通过udpSocket服务的receive方法将数据存入定义好的数据报包
ds.receive(dp);
//4、通过数据报包的方法来获取不同的方法
Stringip =dp.getAddress().getHostAddress();
Stringdata =new String(dp.getData(), 0,dp.getLength());
int port =dp.getPort();
System.out.println(ip+"::"+ data+ "::"+ port);
}
//5、关闭资源
//ds.close();
}
}
(1). 错误的启动顺序
[1].先启动发送端,再启动接收端
[2]. 此时运行结果:
还没等接收端运行完,发送端已经运行完成。这样发送端发送的数据没有正确发送到接收端,数据丢失。
(2). 正确的启动顺序
[1]. 分析:先启动接收端,再启动发送端的可行性
由于接收端的DatagramSocket端点中含有对DatagramSocket的receive方法调用,这个方法是阻塞式的方法。
{1}. 由于接收端的程序先运行,所以开始接收端没有数据报包。因此接收端的程序运行到receive方法之后,就阻塞停在那里,等待有数据报包发送过来。
{2}. 此时再启动发送端的程序,发送端会发送数据报包。这时候接收端就会接到这个数据报包。这样发送端的程序可以正确执行完成,并且发送的数据被接收端正确接收。因此这种方式的启动顺序是可行的。
(3). 运行结果
[1]. 先启动接收端的Socket服务,程序运行到receive方法之后,阻塞停下来等待有数据报包发送过来。
[2]. 再启动发送端的Socket服务,程序一下运行完成,同时接收端接收到发送端发送来的数据。
----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------