Android广播--实现基于UDP协议通信
一、什么是UDP协议
我们最常听到的就是TCP与UDP的区别,首先要明白TCP/IP网络模型,TCP/IP是互联网相关的各类协议族的总称,之所以命名为tcp/IP,是因为TCP、IP协议是两个很重要的协议。
这些协议可划分为四层:数据链路层、网络层、传输层、应用层。
应用层:文件传输、电子邮件、文件服务、虚拟终端
- 超文本传输协议(HTTP):万维网的基本协议
- 远程登陆(Telnet):提供远程访问其它主机功能,允许用户登录internet主机,并在这台主机上执行命令
- 文件传输:TFTP(简单文件传输协议)
- 网络管理:SNMP(简单网络管理协议),提供监控网络设备的方法
- 域名系统:(DNS),用于在internet中将域名及其公共广播的网络节点转换成IP地址
网络层:为数据包选择路由
- Internet协议:IP协议
- Internet控制信息协议(ICMP)
- 地址解析协议(ARP)
- 反向地址解析协议(RARP)
数据链路层:传输有地址的帧以及错位检测功能
传输层:提供端对端的接口(TCP、UDP)
关于TCP与UDP的区别,最重要的一点就是:tcp需要三次握手,而udp是面向无连接的,就是指定ip和端口号,可以无限制的发送数据包
二、UDP协议的通信流程
1.创建套接字:
UDP协议是一种不可靠的网络协议,在通信的两端各建立一个socket套接字,这两个socket只是发送、接收数据的对象,
Java提供了DatagramSocket类,作为基于UDP协议的Socket
2.创建数据,并把数据打包
Java中提供了DatagramPacket类,作为UDP通信中的数据包,所有的数据都可以构建成一个DatagramPacket
3.发送、接收数据
DatagramSocket类中,提供了send()和receive()方法,用来发送和接收数据,不过要注意创建缓冲区,使用byte[]即可
4.关闭
完成UDP通信,要记得关闭套接字DatagramSocket,释放资源
三、UDP广播的分类
1.广播与单播:
广播UDP与单播UDP的区别就是IP地址不同,广播使用广播地址255.255.255.255,将消息发送到同一广播网络上的每个主机。
注意:本地广播信息是不会被路由器转发。
2.多播:
多播,也称为“组播”,将网络中同一业务类型主句进行了逻辑上的分组,进行数据收发的时候,其数据仅仅在同一分组中进行,其他的主机没有加入此分组不能收发对应的数据。
在广域网上广播的时候,其中的交换机和路由器只向需要获取数据的主机复制并转发数据。主机可以向路由器请求加入或退出某个组,网络中的路由器和交换机有选择地复制并传输数据,将数据仅仅传输给组内的主机。多播的这种功能,可以一次将数据发送到多个主机,又能保证不影响其他不需要(未加入组)的主机的其他通信。
3.广域网的多播
多播的地址特定的,D类地址用于多播。D类IP地址就是多播IP地址,即224.0.0.0至239.255.255.255之间的IP地址,并被划分为局部连接多播地址、预留多播地址和管理权限多播地址3类。
1、局部多播地址:在224.0.0.0~224.0.0.255之间,这是为路由协议和其他用途保留的地址,路由器并不转发属于此范围的IP包。
2、预留多播地址:在224.0.1.0~238.255.255.255之间,可用于全球范围(如Internet)或网络协议。
3、管理权限多播地址:在239.0.0.0~239.255.255.255之间,可供组织内部使用,类似于私有IP地址,不能用于Internet,可限制多播范围。
四、Android实现基于UDP协议的通信
1.发送端
创建套接字
DatagramSocket ds = new DatagramSocket();
创建一个缓冲区
byte[] requestDataBytes = data;//data为数据包中数据
创建数据包
DatagramPacket requestPacket = new DatagramPacket(requestDataBytes,
requestDataBytes.length);
指定IP和端口号,“255.255.255.255”为广播,单播的话指定对应的ip即可
requestPacket.setAddress(InetAddress.getByName("255.255.255.255"));
requestPacket.setPort(30000);
发送数据
ds.send(requestPacket);
关闭套接字
ds.close();
2.接收端
创建套接字,需要指定监听的端口号
DatagramSocket ds = new DatagramSocket(30000);
创建缓冲区,缓冲区大小根据需要指定
final byte[] buf = new byte[512];
创建数据包
DatagramPacket receivePack = new DatagramPacket(buf, buf.length);
开始接收
ds.receive(receivePack);
从接收的数据包中可以直接获取发送端的ip、端口号及数据内容
String ip = receivePack.getAddress().getHostAddress();//发送者的ip
int port = receivePack.getPort();//发送者的端口
int dataLen = receivePack.getLength();//数据包长度
String data = new String(receivePack.getData(), 0, dataLen);//数据内容
关闭套接字
ds.close();
完整代码如下:使用时,应先调用start()创建监听线程,然后根据需要发送数据
public static void sendBroadcast(byte[] data) throws IOException {
// 作为搜索方,无需指定端口,让系统自动分配
DatagramSocket ds = new DatagramSocket();
//发送一份请求数据,暴露监听端口
byte[] requestDataBytes = data;
//创建一个DatagramPacket
DatagramPacket requestPacket = new DatagramPacket(requestDataBytes,
requestDataBytes.length);
//指定接收方的ip地址
requestPacket.setAddress(InetAddress.getByName("255.255.255.255"));
//指定接收方的端口号
requestPacket.setPort(30000);
//开始发送广播
ds.send(requestPacket);
ds.close();
}
private static class Listener extends Thread {
private final int listenPort;
private final CountDownLatch countDownLatch;
private final List<Device> devices = new ArrayList<>();
private boolean done = false;
private DatagramSocket ds = null;
public Listener(int listenPort, CountDownLatch countDownLatch) {
super();
this.listenPort = listenPort;
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
super.run();
//通知已启动
countDownLatch.countDown();
try {
//监听回送端口
ds = new DatagramSocket(listenPort);
while (!done) {
//构建接收实体
final byte[] buf = new byte[10000];
DatagramPacket receivePack = new DatagramPacket(buf, buf.length);
//开始接收
ds.receive(receivePack);
//打印接收到的信息与发送者的信息
String ip = receivePack.getAddress().getHostAddress();//发送者的ip
int port = receivePack.getPort();//发送者的端口
int dataLen = receivePack.getLength();//数据包长度
String data = new String(receivePack.getData(), 0, dataLen);//数据内容
byte[] audio = new byte[data.length()];
System.arraycopy(receivePack.getData(), 0, audio, 0, data.length());
AudioModule.getInstance().udpadd(audio);
}
} catch (Exception e) {
} finally {
close();
}
}
private void close() {
if (null != ds) {
ds.close();
ds = null;
}
}
private static Listener listen() throws InterruptedException {
Log.d(TAG,"UDPSearcher start listen");
CountDownLatch countDownLatch = new CountDownLatch(1);
Listener listener = new Listener(LISTENER_PORT, countDownLatch);
listener.start();
countDownLatch.await(); //等待监听启动完成,这里是阻塞的
return listener;//启动完成就返回监听
}
public static void start() {
try {
Listener listener = listen();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
上一篇: django中的orm操作
下一篇: Photoshop 简洁红色圣诞壁纸制作