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

news2024/11/26 13:46:07

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() {
    @Override
    public void onSuccess() {
        appendLog("创建群组成功");
        // 在这里可以创建ServerSocket并等待客户端接入
        ...
    }

    @Override
    public 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() {
    @Override
    public 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();
    }

    @Override
    public 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) {
                	// 群组已形成,但本设备非群主
                    // 获取群主 IP
                    String 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() {
     @Override
     public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice srcDevice) {

     }
 }

WifiP2pManager.DnsSdTxtRecordListener txtListener = new WifiP2pManager.DnsSdTxtRecordListener() {
    @Override
    public void onDnsSdTxtRecordAvailable(String fullDomainName, Map<String, String> txtRecordMap, WifiP2pDevice srcDevice) {

    }
}
mManager.setDnsSdResponseListeners(mChannel, ptrListener, txtListener);

// UPnP服务监听器
private WifiP2pManager.UpnpServiceResponseListener upnpListener = new  WifiP2pManager.UpnpServiceResponseListener() {

    @Override
    public 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.coloradmin.cn/o/1042666.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

链动2+1模式:如何用二级分销打造高效团队,实现销量突破

你是否想要拥有一个高效的团队&#xff0c;让你的销量快速提升&#xff1f;你是否厌倦了传统的多层级分销模式&#xff0c;觉得它太复杂、太难管理、太不合规&#xff1f;你是否想要找到一种简单、合理、合法的商业模式&#xff0c;让你的收益稳定、可持续、可复制&#xff1f;…

【深度学习实验】卷积神经网络(三):自定义二维卷积神经网络:步长和填充、输入输出通道

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入必要的工具包 1. 步长、填充 a. 二维互相关运算&#xff08;corr2d&#xff09; b. 二维卷积层类&#xff08;Conv2D&#xff09; c. 模型测试 d. 代码整合 2. 输入输出通道 a…

前缀树-Trie树

前缀树—Trie树&#xff0c;也叫作“单词查找树”、“字典树” 它属于多叉树结构&#xff0c;典型应用是用于统计&#xff0c;排序和保存大量的字符串&#xff08;但不仅限于字符串&#xff09;&#xff0c;所以经常被搜索引擎系统用于文本词频统计。它的优点是&#xff1a;利…

【前段基础入门之】=>玩转【CSS】开篇章!

目录 CSS 的简介&#xff1a;CSS的编写位置行内样式内部样式外部样式 样式表的优先级CSS语法规范&#xff1a; 总结&#xff1a; CSS 的简介&#xff1a; 层叠样式表&#xff08;Cascading Style Sheets&#xff0c;缩写为 CSS&#xff09;是一种样式表语言&#xff0c;用来描述…

前端项目练习(练习-007-typescript-02)

学习前&#xff0c;首先&#xff0c;创建一个web-007项目&#xff0c;内容和web-006一样。&#xff08;注意将package.json中的name改为web-007&#xff09; 前面的例子&#xff0c;我们使用了nodejswebpack&#xff0c;成功创建了包含html&#xff0c;ts&#xff0c;css三个文…

【.net core】使用nssm发布WEB项目

nssm下载地址&#xff1a;NSSM - the Non-Sucking Service Manager 配置方式 修改服务在nssm工具下输入命令:nssm edit jntyjr 其中 jntyjr为添加服务时设置的Service name nssm可以设置任何以参数启动的应用程序以服务形式启动,通过设置参数内容启动服务 以上配置等同于执行…

ReferenceError: primordials is not defined错误解决

问题场景&#xff1a; 从github上拉了一个项目&#xff0c;想要学习一下&#xff0c;在起服务的时候出现了这个问题。 造成的原因&#xff1a; gulp 与 node 版本起冲突。 1&#xff09;首先&#xff0c;安装 gulp&#xff0c;查看版本&#xff1b; npm install gulp -g g…

如何设计科研问卷?

问卷研究法的最大特点在于能在较短时间内调查很多研究对象取得大量的资料&#xff0c;并能对资料进行数量化处理&#xff0c;经济省时&#xff0c;因此是教育研究中使用频率较高、用途较广泛的一种研究方法。问卷研究法的关键在于设计一份信度、效度较高&#xff0c;内容合理的…

二维码怎么分解成链接?线上快速解码教学

怎么分解二维码呢&#xff1f;有些时候我们需要将二维码图片分解成链接使用&#xff0c;所以想要使用解码功能一般都需要通过二维码生成器工具来完成。那么如何在线将二维码分解成链接呢&#xff0c;可能有些小伙伴还不知道怎么操作&#xff0c;下面就给大家分享一下免费二维码…

较真儿学源码系列-PowerJob时间轮源码分析

PowerJob版本&#xff1a;4.3.2-main。 之前分析过PowerJob的启动流程源码&#xff0c;感兴趣的可以查看《较真儿学源码系列-PowerJob启动流程源码分析》 1 简介 试想一下&#xff0c;如果此时有一个需要延迟3s执行的任务&#xff0c;你会怎么实现呢&#xff1f;一种常规的思路…

洗地机哪个牌子好用又实惠?口碑最好的洗地机推荐

智能技术飞速发展的时代&#xff0c;扫地机器人这类智能家电其实也在顺应潮流和用户需求&#xff0c;不断更新迭代。暂且不说市面上现有多少个洗地机品牌&#xff0c;单单一个洗地机品牌旗下&#xff0c;其实每年都会有多个系列的新品亮相&#xff0c;我们面对的选择多了&#…

Python交叉验证实现

目录 <font colorblue size4 face"楷体">HoldOut 交叉验证<font colorred size4 face"楷体">K 折交叉验证<font colorblue size4 face"楷体">分层 K 折交叉验证<font colorblue size4 face"楷体">Leave P Out…

融云 CallPlus + X,通话场景一站式解决方案

融云近期上线的 CallPlus SDK&#xff0c;针对音视频呼叫场景单独设计后端服务 Call Server&#xff0c;信令延时低至 150ms&#xff0c;确保各端计时准确、一致&#xff1b;上线了音视频通话互转、灵活的多人通话、通话记录管理能力等功能。关注【融云全球互联网通信云】了解更…

掌动智能兼容性测试有哪些优势

兼容性测试为企业带来市场竞争优势&#xff0c;并提高用户满意度。在软件开发过程中&#xff0c;将兼容性测试作为一个重要的环节&#xff0c;将为企业的成功和用户满意度打下坚实的基础。那么&#xff0c;掌动智能兼容性测试的具体优势是什么?下面&#xff0c;就来看看具体介…

【面试题】说说你对 async和await 理解

前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 表妹一键制作自己的五星红旗国庆头像&#xff0c;超好看 async await详解 原理&#xff1a; async声明该函数是异步的&#xff0c;且该函数会返回一个…

比例导引详解(Proportional navigation guidance,PNG)-及Python程序

模型算法推导 比例导引是一种制导算法&#xff0c;其经典程度相当于控制器中的PID&#xff0c;在本文中&#xff0c;只对其二维平面的情况做分析&#xff0c;考虑一个拦截弹拦截机动目标&#xff08;固定目标相当于目标速度为0&#xff09;&#xff0c;其运动如下图所示&#…

变配电智能化系统:提高效率与安全性

随着科技的发展&#xff0c;电力系统正在逐步向智能化、数字化方向转型。变配电系统作为电力系统的重要组成部分&#xff0c;其智能化水平直接影响着电力系统的运行效率和稳定性。 一、系统概述 力安科技变配电智能化系统是一种采用先进技术&#xff0c;实现对变配电设…

DD5 进制转换

目录 一、题目 二、分析 三、代码 一、题目 进制转换_牛客题霸_牛客网 二、分析 三、代码 #include <iostream> #include <vector> #include <string> using namespace std; string Greater_than_Ten(int digit)//余数大于等于10的时候转换成对应的字母…

低照度增强算法(图像增强+目标检测+代码)

本文介绍 在增强低光图像时&#xff0c;许多深度学习算法基于Retinex理论。然而&#xff0c;Retinex模型并没有考虑到暗部隐藏的损坏或者由光照过程引入的影响。此外&#xff0c;这些方法通常需要繁琐的多阶段训练流程&#xff0c;并依赖于卷积神经网络&#xff0c;在捕捉长距…

从零搭建开发脚手架 顺应潮流开启升级 - SpringBoot 从2.x 升级到3.x

文章目录 涉及升级项导入包修改SpringBoot3.x中spring.factories功能被移除 涉及升级项 升级JDK 8 -> JDK17 Spring Boot 2.3.7 -> Spring Boot 3.1.3 Mysql5.7.x -> Mysql8.x Mybatis-Puls 3.4.2 -> 3.5.3 knife4j 2.x -> 4.3.x sa-token 1.24.x -> 1.…