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连接。这种方式会根据服务提供的字段和协议来判断是否符合连接要求。

服务创建

  1. 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参数指定了应用程序使用的协议和传输层。

  2. 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/121059.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uniapp h5 端 router.base设置history后仍有#号

manifest.json文件设置&#xff1a; "h5": { "router": { "base": "./", "mode": "history" }, }按相对路径发行时路由模式强制为hash模式&#xff0c;不支持history模式&#xff08;两者相悖&#xff09;…

Spring Security 简单token配置

Spring Security 简单token配置 说明&#xff1a;非表单配置 先上码&#xff1a; https://gitee.com/qkzztx_admin/security-demo/tree/master/demo-two 环境&#xff1a;win10 idea2023 springboot2.7.6 maven3.8.6 代码清单说明 依赖&#xff1a; <dependency><…

算法的时间复杂度分析习题专题

之前写了一篇重点是讲理论&#xff0c;今天重点在于对于题目的分析 题目难度不分先后&#xff0c;有题目来源会直接给出链接或者位置 第一题&#xff1a;消失的数字 题目来源&#xff1a;LeetCode消失的数字 分析 第一种思路分析&#xff1a; 参考代码&#xff1a; #include …

CTP:关于cc和bindgen库及rust工程组织

有三个工程目录&#xff0c;cpt-api, ctp-sdk,ctp-strategy 1、ctp-sdk&#xff1a; 主要的目的是基于bindgen库生成与cpp的.h文件相对应一个binding.rs文件&#xff0c;后面供策略使用。 在这个目录下&#xff0c;建一个build.rs,用bindgen库生成cpp.h的头文件相应的rust绑定…

nodejs+vue 网上招聘系统elementui

第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;技术背景 5 3.2.2经济可行性 6 3.2.3操作可行性&#xff1a; 6 3.3 项目设计目标与原则 6 3.4系统流程分析 7 3.4.1操作流程 7 3.4.2添加信息流程 8 3.4.3删除信息流程 9 第4章 系统设计 11 …

linux-定时任务

目录 一、crond命令 1、什么是计划任务 2、crond服务的概念 3、crontab 二、at命令 1、at任务的概念 三、邮件服务 1、概念 2、启动postfix 四、mailx命令 1、三个概念&#xff1a; 2、交互式发邮件 3、非交互式发邮件 四、cron定时任务实践 1、系统定时任务配置…

【HUAWEI】单臂路由

目录 ​ &#x1f96e;写在前面 &#x1f96e;2.1、拓扑图 &#x1f96e;2.2、操作思路 &#x1f96e;2.3、配置操作 &#x1f363;2.3.1、LSW4配置 &#x1f363;2.3.2、R2配置 &#x1f363;2.3.3、测试网络 &#x1f990;博客主页&#xff1a;大虾好吃吗的博客 &…

Cruise 从零搭建模型

第一步&#xff0c;新建一个project&#xff1a; 下面添加version&#xff1a; 将该新建的task加载进来&#xff0c;然后保存&#xff1a; 保存完之后&#xff0c;文件夹内多了很多内容&#xff1a; .prj 文件是工程文件。 .bdf 是存放模型里面的数据的文件。 可以看出&#…

ElementUI之首页导航+左侧菜单->mockjs,总线

mockjs总线 1.mockjs 什么是Mock.js 前后端分离开发开发过程当中&#xff0c;经常会遇到以下几个尴尬的场景&#xff1a; - 老大&#xff0c;接口文档还没输出&#xff0c;我的好多活干不下去啊&#xff01; - 后端小哥&#xff0c;接口写好了没&#xff0c;我要测试啊&#x…

springcloud之自我介绍

写在前面 在这篇文章 中我们分析了单体应用的问题&#xff0c;以及用来解决这些问题的解决的方案微服务&#xff0c;并接着看了微服务需要考虑的各种&#xff0c;如服务调用&#xff0c;负载均衡&#xff0c;服务治理&#xff0c;链路追踪&#xff0c;分布式事务&#xff0c;等…

Linux多线程【线程互斥与同步】

✨个人主页&#xff1a; 北 海 &#x1f389;所属专栏&#xff1a; Linux学习之旅 &#x1f383;操作环境&#xff1a; CentOS 7.6 阿里云远程服务器 文章目录 &#x1f307;前言&#x1f3d9;️正文1、资源共享问题1.1、多线程并发访问1.2、临界区与临界资源1.3、“锁” 概念引…

用于自然语言处理的 Python:理解文本数据

一、说明 Python是一种功能强大的编程语言&#xff0c;在自然语言处理&#xff08;NLP&#xff09;领域获得了极大的普及。凭借其丰富的库集&#xff0c;Python 为处理和分析文本数据提供了一个全面的生态系统。在本文中&#xff0c;我们将介绍 Python for NLP 的一些基础知识&…