Wi-Fi直连分享:Android设备间的高速连接

Wi-Fi直连分享:Android设备间的高速连接
引言
随着无线局域网(Wi-Fi)的普及和发展,使用Wi-Fi直连技术(P2P)在没有中间接入点的情况下实现设备间直接互联成为可能。通过Wi-Fi直连,具备相应硬件的Android 4.0及更高版本设备可以实现高速连接通信,比传统蓝牙连接具有更远的传输距离。这项技术对于多人游戏、照片共享等需要设备间数据共享的应用非常有用。
Wi-Fi直连的核心API是WifiP2pManager类。
普通连接,代码实现
初始化
private WifiP2pManager.Channel mChannel; // app与framework联系的纽带
private WifiP2pManager mManager;
...
mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mManager.initialize(this, getMainLooper(), null);
创建群组
只有服务端设备需要执行此步骤,客户端设备可以跳过。即使不创建群组,设备仍然可以进行后续的设备发现和连接操作。一旦连接成功,这两台设备将自动形成一个群组,并在其中选择一台设备作为群主。创建群组后,会在Wi-Fi列表中出现一个名为DIRECT_**_DeviceName的网络,这个网络是为没有Wi-Fi直连功能的设备准备的,它们可以通过连接此网络来加入群组。但是使用此方式加入的设备不会收到WIFI_P2P_CONNECTION_CHANGED_ACTION广播,不过在调用mManager.requestGroupInfo时,可以获取到这些设备的信息。
mManager.createGroup(mChannel, new WifiP2pManager.ActionListener() {@Overridepublic void onSuccess() {appendLog("创建群组成功");// 在这里可以创建ServerSocket并等待客户端接入...}@Overridepublic void onFailure(int reason) {appendLog("创建群组失败");...}
});
很多地方都会使用到WifiP2pManager.ActionListener回调,下面列出了一些可能的错误原因:
/*** Wi-Fi直连操作失败*/
public static final int ERROR = 0;/*** 设备不支持Wi-Fi直连功能*/
public static final int P2P_UNSUPPORTED = 1;/*** 操作失败,框架忙于处理其他请求*/
public static final int BUSY = 2;/*** 操作失败,未添加任何服务请求*/
public static final int NO_SERVICE_REQUESTS = 3;
发现设备
mManager.discoverPeers(mChannel, mActionListener);
客户端设备直接执行此操作,不需要创建群组。两台设备必须同时执行设备发现操作,才能相互发现对方的存在。
停止发现设备
mManager.stopPeerDiscovery(mChannel, mActionListener);
连接设备
连接设备的操作可以由服务端或客户端发起。device是通过设备发现获得的对方设备信息,后续会介绍广播的相关内容。
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
mManager.connect(mChannel, config, mActionListener);
取消连接
连接后也可以取消连接。注意:取消操作将取消所有正在发起连接邀请的设备,不能针对单个设备进行操作。
mManager.cancelConnect(mChannel, mActionListener);
解散群组
当需要取消某个单一连接时,只能从客户端取消对服务端的连接。如果需要取消所有连接,只能通过解散群组来实现。
mManager.removeGroup(mChannel, mActionListener);
获取群组相关信息
可以通过以下代码获取群组中的所有设备信息:
mManager.requestGroupInfo(mChannel, new WifiP2pManager.GroupInfoListener() {@Overridepublic void onGroupInfoAvailable(WifiP2pGroup group) {appendLog("已连接的设备:");Collection<WifiP2pDevice> devices = group.getClientList();int i=1;for(WifiP2pDevice d: devices) {appendLog((i++) +": ip:" +d.deviceAddress+", name:" +d.deviceName +", isGroupOwner:" +d.isGroupOwner() );}}
});
广播实现
使用广播来通知应用层自身设备、发现设备和连接设备的状态变化。
| Intent | 说明 |
|---|---|
WIFI_P2P_CONNECTION_CHANGED_ACTION | 当设备的 WLAN 连接状态更改时广播。 |
WIFI_P2P_PEERS_CHANGED_ACTION | 当您调用 discoverPeers() 时广播。如果您在应用中处理此 Intent,则通常需要调用 requestPeers() 以获取对等设备的更新列表。 |
WIFI_P2P_STATE_CHANGED_ACTION | 当 WLAN P2P 在设备上启用或停用时广播。 |
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION | 当设备的详细信息(例如设备名称)更改时广播。 |
WIFI_P2P_DISCOVERY_CHANGED_ACTION | 当设备开始或停止发现设备时广播 |
下面是一个实现广播接收器的示例:
public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {public WiFiDirectBroadcastReceiver() {super();}@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {// 检查 Wi-Fi 是否启用并通知相应的活动int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, WifiP2pManager.WIFI_P2P_STATE_DISABLED);// wifi p2p 能否使用取决于你的 Wi-Fi 是否已打开。if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {// wifi p2p 可用} else if (state == WifiP2pManager.WIFI_P2P_STATE_DISABLED) {// wifi p2p 不可用}} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {// 调用 WifiP2pManager.requestPeers() 获取当前对等设备列表// 获取所有扫描到的设备。WifiP2pDeviceList mPeers = intent.getParcelableExtra(WifiP2pManager.EXTRA_P2P_DEVICE_LIST);} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {// 处理新连接或断开连接的情况// wifi p2p 连接状态发生变化,在创建组成功时也会触发该广播。// 获取 Wi-Fi P2P 网络状态NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);// 关于该群组的连接信息。有三个属性:// 1. groupFormed:群组是否已形成,作为群主,创建群组后获得的该属性值为 true// 2. isGroupOwner:本设备是否为群主// 3. groupOwnerAddress:群主的 IP 地址WifiP2pInfo p2pInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO);// 群组的相关信息,如网络名称、密码和所有已连接设备等。WifiP2pGroup p2pGroup = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP);if (networkInfo != null && networkInfo.isConnected()) {// 表明已连接上,创建组成功也会进入该判断if (p2pInfo.groupFormed && p2pInfo.isGroupOwner) {// 群组已形成,且本设备为群主} else if (p2pInfo.groupFormed) {// 群组已形成,但本设备非群主// 获取群主 IPString groupOwnerAddress = p2pInfo.groupOwnerAddress.getHostAddress();// 建立 Socket 连接}}} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {// 处理本设备的 Wi-Fi 状态变化// 本设备信息发生变化WifiP2pDevice wifiP2pDevice = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);} else if (WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION.equals(action)) {// 处理发现设备操作状态变化// WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED:停止状态// WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED:开始状态int discoveryState = intent.getIntExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE,WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED);}}
}
获取连接信息
上述代码片段展示了如何使用WifiP2pManager来获取连接信息。通过调用requestConnectionInfo()方法,并传入一个ConnectionInfoListener,我们可以在连接信息可用时得到回调。
- 如果连接信息为null或群主地址为空,直接返回。
- 如果群已建立,且设备是群主,可以通过
requestGroupInfo()方法获取群组信息,其中包括WiFi热点密码。
对于客户端设备,可以根据需要执行相应的操作。
针对性WiFi P2P连接
除了普通的搜索和连接方式外,还可以使用WifiP2pManager.discoverServices()方法进行针对性的WiFi P2P连接。这种方式会根据服务提供的字段和协议来判断是否符合连接要求。
服务创建
-
Bonjour
使用Bonjour服务时,可以通过创建txt记录来指定相关信息。
示例代码如下:
Map<String, String> txtRecord = new HashMap<String, String>(); txtRecord.put("txtvers", "1"); txtRecord.put("pdl", "application/postscript"); mServiceInfo = WifiP2pDnsSdServiceInfo.newInstance(instanceName,serviceType, txtRecord);其中,
serviceType参数指定了应用程序使用的协议和传输层。 -
UPnP
使用UPnP服务时,可以指定服务类型和相关信息。
示例代码如下:
List<String> services = new ArrayList<String>(); services.add("urn:schemas-upnp-org:service:AVTransport:1"); services.add("urn:schemas-upnp-org:service:ConnectionManager:1"); mServiceInfo = WifiP2pUpnpServiceInfo.newInstance("6859dede-8574-59ab-9332-123456789011","urn:schemas-upnp-org:device:MediaRenderer:1",services);
添加服务
创建完服务信息后,可以使用addLocalService()方法将服务添加到本地。
示例代码如下:
mManager.addLocalService(mChannel, mServiceInfo, mActionListener);
创建群组
与之前的示例相同,可以使用相同的方法来创建WiFi P2P群组。
创建服务监听
针对Bonjour和UPnP服务,可以分别创建相应的监听器。当搜索到设备服务时,这些监听器会得到回调。
示例代码如下:
// Bonjour服务监听器
WifiP2pManager.DnsSdServiceResponseListener ptrListener = new WifiP2pManager.DnsSdServiceResponseListener() {@Overridepublic void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice srcDevice) {}}WifiP2pManager.DnsSdTxtRecordListener txtListener = new WifiP2pManager.DnsSdTxtRecordListener() {@Overridepublic void onDnsSdTxtRecordAvailable(String fullDomainName, Map<String, String> txtRecordMap, WifiP2pDevice srcDevice) {}
}
mManager.setDnsSdResponseListeners(mChannel, ptrListener, txtListener);// UPnP服务监听器
private WifiP2pManager.UpnpServiceResponseListener upnpListener = new WifiP2pManager.UpnpServiceResponseListener() {@Overridepublic void onUpnpServiceAvailable(List<String> uniqueServiceNames, WifiP2pDevice srcDevice) {}
}
mManager.setUpnpServiceResponseListener(mChannel, upnpListener);
这些监听器会在搜索到设备服务时得到回调。根据搜索时传入的服务request,决定回调哪个监听器。
发现服务
通过创建相应的服务请求,可以发现Bonjour和UPnP服务。
示例代码如下:
// Bonjour类型的TXT服务,对应上面 txtListener
WifiP2pDnsSdServiceRequest txtRequest = WifiP2pDnsSdServiceRequest.newInstance(INSTANCE_NAME, SERVICE_TYPE);
// Bonjour类型的PTR服务,对应上面 ptrListener
WifiP2pDnsSdServiceRequest ptrRequest = WifiP2pDnsSdServiceRequest.newInstance(SERVICE_TYPE);
// UPnP服务,对应上面的upnpListener
WifiP2pUpnpServiceRequest upnpRequest = WifiP2pUpnpServiceRequest.newInstance(searchTarget);mManager.addServiceRequest(mChannel, txtRequest, mActionListener);
mManager.addServiceRequest(mChannel, ptrRequest, mActionListener);
mManager.addServiceRequest(mChannel, upnpRequest, mActionListener);
其余步骤与之前的示例相同。
以上是针对性WiFi P2P连接的示例代码和步骤。你可以根据自己的需求来选择合适的服务类型和设置相应的监听器来处理搜索到的设备服务。
参考
参考文档:https://developer.android.google.cn/guide/topics/connectivity/wifip2p?hl=zh-cn
相关文章:
Wi-Fi直连分享:Android设备间的高速连接
Wi-Fi直连分享:Android设备间的高速连接 引言 随着无线局域网(Wi-Fi)的普及和发展,使用Wi-Fi直连技术(P2P)在没有中间接入点的情况下实现设备间直接互联成为可能。通过Wi-Fi直连,具备相应硬件…...
LeetCode 面试题 05.06. 整数转换
文章目录 一、题目二、Java 题解 一、题目 整数转换。编写一个函数,确定需要改变几个位才能将整数A转成整数B。 示例1: 输入: A 29 (或者0b11101), B 15(或者0b01111) 输出: 2 示例2: 输入&a…...
增强for循环和一般for循环的对比使用
文章底部有个人公众号:热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。个人B站主页热爱技术的小郑 ,视频内容主要是对应文章的视频讲解形式。有兴趣的可以关注一下。为何分享? 踩过的坑没必要让别人在再踩,自己复盘…...
云原生之使用Docker部署RSS阅读器Huntly
云原生之使用Docker部署RSS阅读器Huntly 一、Huntly介绍1.1 Huntly简介1.2 Huntly功能2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载Huntly镜像五、部署Huntly5.1 创建挂载目录5.2 创建Hun…...
Powershell 实现禁用密码复杂性,空密码
前提条件 开启wmi,配置网卡,参考 实现一键关闭密码策略和远程空密码登录 最近客户需要的一个无法理解的需求,需要远程登录不输入密码,安全性没有了还要实现,没办法客户是上帝,客户怎么开心怎么来都行,安全性问题告知不重视,实际环境不建议一下操作,只要联网你被黑的哦…...
【c语言】详解动态内存管理
目录 关于动态内存分配malloc和calloc函数介绍动态内存回收----freerealloc函数介绍常见的动态内存错误 关于动态内存分配 回想一下我们之前学过的内存开辟方式: int val 20;//在栈空间上开辟四个字节 char arr[10] {0};//在栈空间上开辟10个字节的连续空间在学…...
深度学习概念——端对端
目录 1、端对端是什么2、端对端有什么用3、例子4、引用 在读论文的过程中反复遇到端对端的概念,就需要理解深刻一些。在此将收集到的一些资料拿出来辅以自己的拙见,请大家多多批评指正! 1、端对端是什么 在计算机学科中有一种算法叫分治法&a…...
苹果触控笔有必要买吗?平价ipad电容笔推荐
其实,市面上的数码类产品很多,有的侧重于美观,有的侧重于功能,有的侧重于性能。与iPad平板电脑搭配使用的电容笔同样也如此。因此,在选购电容笔时,一定要了解有关电容笔的知识。在购买之前,一定…...
React的高阶函数
1.认识高阶函数 高阶组件 本身不是一个组件,而是一个函数函数的参数是一个组件,返回值也是一个组件 高阶组件的定义 import ThemeContext from "../context/theme_context"function withTheme(OriginComponent) {return (props) > {retur…...
Java8实战-总结34
Java8实战-总结34 重构、测试和调试使用 Lambda 重构面向对象的设计模式观察者模式责任链模式 重构、测试和调试 使用 Lambda 重构面向对象的设计模式 观察者模式 观察者模式是一种比较常见的方案,某些事件发生时(比如状态转变)࿰…...
uniapp项目实践总结(二十四)安卓平台 APP 打包教程
导语:当你的应用程序开发完成后,在上架安卓应用商店之前,需要进行打包操作,下面简单介绍一下打包方法。 目录 准备工作配置项目生成证书打包配置准备工作 在打包之前,请保证你的 uniapp 应用程序编译到安卓手机模拟器的 App 是可以正常运行的,APP 打包分为安卓和 ios 两…...
GeoServer地图服务器权限控制
目录 1下载相关软件 2部署软件 3配置鉴权环节 4Java工程 5测试鉴权 6测试鉴权结果分析 本文章应该会后面试验一个鉴权功能就会发布一系列测试过程(GeoServer有很多鉴权方式) 1Download - GeoServer 1下载相关软件 进入geoserver官网的下载页面 …...
Python+requests+unittest+excel实现接口自动化测试框架
一、框架结构: 工程目录 二、Case文件设计 三、基础包 base 3.1 封装get/post请求(runmethon.py) 1 import requests2 import json3 class RunMethod:4 def post_main(self,url,data,headerNone):5 res None6 if heade…...
25807-2020 间脲基苯胺盐酸盐 课堂随笔
声明 本文是学习GB-T 25807-2020 间脲基苯胺盐酸盐. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了间脲基苯胺盐酸盐的要求、采样、试验方法、检验规则以及标志、标签、包装、运输和 贮存。 本标准适用于间脲基苯胺盐酸盐产品…...
苹果手机通讯录联系人如何一键删除? 1个方法轻松解决!
手机通讯录里存了上百个之前公司客户的电话,结果苹果手机不支持一键清空联系人。有什么其他办法可以将这些联系人一次性全部删除吗? 随着时间的增长,手机通讯录中难免会积累许多不再联系的用户或者是已经失效的联系人。对于这些许久不联系的人…...
【Linux成长史】Linux编辑器-gcc/g++使用
🎬 博客主页:博主链接 🎥 本文由 M malloc 原创,首发于 CSDN🙉 🎄 学习专栏推荐:LeetCode刷题集 数据库专栏 初阶数据结构 🏅 欢迎点赞 👍 收藏 ⭐留言 📝 如…...
【CNN-FPGA开源项目解析】卷积层03--单格乘加运算单元PE 单窗口卷积块CU 模块
03–单格乘加运算单元PE & 单窗口卷积块CU 文章目录 03--单格乘加运算单元PE & 单窗口卷积块CU前言单格乘加运算单元PE代码模块结构时序逻辑分析对其上层模块CU的要求 单窗口卷积块CU代码逻辑分析 前言 第一和第二篇日志已经详细阐述了"半精度浮点数"的加…...
一文教你学会ArcGIS Pro地图设计与制图系列全流程(2)
ArcGIS Pro做的成果图及系列文章目录: 系列文章全集: 《一文教你学会ArcGIS Pro地图设计与制图系列全流程(1)》《一文教你学会ArcGIS Pro地图设计与制图系列全流程(2)》《一文教你学会ArcGIS Pro地图设计与…...
ICML 2017: 基于卷积的Seq2Seq解决方案
一.文章概述 通常而言,Seq2Seq解决方案一般都采用循环神经网络,但在本文,作者提出了基于卷积神经网络的解决方案ConvS2S。基于卷积神经网络的方案有两大优势:计算并行化更高,优化更容易(非线性的数量是固定…...
探索GmSSL+Nginx实践及原理
前言 随着大国崛起步伐的迈进,敏感单位的数据安全问题越发受到重视,数据的加密安全传输尤为重要,对于安全问题,国家自研加密算法提供了有力的保障。 作为信创行业的国有企业,十分有必要在网络通信中使用国密算法加密…...
Simple Runtime Window Editor:突破游戏窗口限制的终极解决方案
Simple Runtime Window Editor:突破游戏窗口限制的终极解决方案 【免费下载链接】SRWE Simple Runtime Window Editor 项目地址: https://gitcode.com/gh_mirrors/sr/SRWE 你是否曾为游戏内置分辨率选项太少而烦恼?是否想在窗口模式下获得全屏游戏…...
从零到一:在个人PC上部署并集成ChatGLM-6B到Unity应用
1. 环境准备与模型下载 在个人PC上部署ChatGLM-6B需要先搞定三件事:硬件检查、软件环境搭建和模型文件获取。我的老款游戏本(i7-9750H RTX2060 6GB显存)实测可以流畅运行,关键在于正确的量化配置。 硬件检查要点: 显存…...
LVGUI字体瘦身实战:如何为你的IoT设备定制一个超小的中文字体库
LGVUI字体瘦身实战:为IoT设备定制超小中文字体库的工程化解决方案 在嵌入式物联网设备开发中,每一KB的Flash和RAM都弥足珍贵。当你的智能温控器需要显示"当前温度:25℃"或者电子秤要呈现"净重:0.5kg"时&#…...
从myplaces.shp到专题地图:手把手教你用QGIS C++ API实现点要素分级渲染
从myplaces.shp到专题地图:QGIS C API实现点要素分级渲染实战指南 当我们需要在桌面GIS应用中直观展示气象站降雨量、城市人口密度或商业网点销售额等连续型空间数据时,分级色彩渲染是最有效的可视化手段之一。本文将深入探讨如何利用QGIS强大的C API&am…...
暗黑3鼠标宏终极指南:D3KeyHelper 5步配置法快速上手
暗黑3鼠标宏终极指南:D3KeyHelper 5步配置法快速上手 【免费下载链接】D3keyHelper D3KeyHelper是一个有图形界面,可自定义配置的暗黑3鼠标宏工具。 项目地址: https://gitcode.com/gh_mirrors/d3/D3keyHelper D3KeyHelper是一款专为暗黑破坏神3玩…...
纯视觉纵深无感管控,落地硐室无人少人化透明值守模式技术白皮书
纯视觉纵深无感管控,落地硐室无人少人化透明值守模式技术白皮书副标题:摒弃井下繁杂传感布设,依靠暗光三维实景重构、深部空间无感感知、盲区跨镜无痕跟踪、身体指纹生物核验,实现井下 24 小时无人值守、全域透明运维前言矿山井下…...
终极FGO自动化助手:告别枯燥刷本,每天节省3小时游戏时间
终极FGO自动化助手:告别枯燥刷本,每天节省3小时游戏时间 【免费下载链接】FGA Auto-battle app for F/GO Android 项目地址: https://gitcode.com/gh_mirrors/fg/FGA Fate/Grand Automata(简称FGA)是一款专为Fate/Grand Or…...
Qdrant Python客户端全解析:从向量数据库连接到AI应用开发实战
1. 项目概述:从向量数据库到客户端,现代AI应用落地的关键拼图如果你最近在折腾大语言模型应用,或者想给自己的产品加上一个“智能大脑”,那你大概率已经听过“向量数据库”这个词了。简单来说,它就像一个专门为AI模型设…...
Arm CoreLink PCK-600电源管理架构与寄存器编程详解
1. Arm CoreLink PCK-600电源控制架构解析在嵌入式系统设计中,电源管理单元(PMU)是实现高效能耗控制的核心组件。Arm CoreLink PCK-600作为业界领先的电源控制解决方案,其架构设计体现了现代SoC电源管理的先进理念。PCK-600系列采…...
WipperSnapper+Adafruit IO:无代码物联网开发实战,从传感器到云端自动化
1. 项目概述与核心价值如果你和我一样,在物联网(IoT)项目初期,常常被复杂的嵌入式编程、网络协议和云平台对接搞得焦头烂额,那么今天分享的这个实战项目,或许能让你眼前一亮。我们这次不谈复杂的代码&#…...
