学习资料:

Demo 下载地址:https://github.com/mengzhinan/WiFi_P2P_test

GoogleAndroid Doc:https://developer.android.google.cn/guide/topics/connectivity/wifip2p

背景介绍:

Wifi P2P (peer to peer):义为 Wifi 点对点,也叫 Wifi 直连(Wifi Direct),他是 Wifi Display(投屏) 应用的技术基础。

官方描述:

使用 WLAN 直连 (P2P) 技术,可以让具备相应硬件的 Android 4.0(API 级别 14)或更高版本设备在没有中间接入点的情况下,通过 WLAN 进行直接互联。使用这些 API,您可以实现支持 WLAN P2P 的设备间相互发现和连接,从而获得比蓝牙连接更远距离的高速连接通信效果。对于多人游戏或照片共享等需要在用户之间共享数据的应用而言,这一技术非常有用。

总结以下优点:

1、有比蓝牙更远的传输距离。未测试

2、有比蓝牙更快速的数据传输速度,更大的带宽。未测试

3、只需要打开 Wifi 即可,不需要加入任何网络或 AP,即可实现对等点连接通讯。

可实现通过 Wifi 连接,同时使用数据网络的场景,比喻:手机遥控无人机的同时,无人机需要访问远程服务器上传数据。

Wifi P2P 架构:

虽然上面提到两台或多台 Android 设备通过 Wifi P2P 通讯时不需要加入任何网络,但是 Wifi P2P 协议还是需要组件网络才能发现对方并建立 TCP 连接通讯的。在组网和通讯阶段一共有 3 个角色:

1、P2P Group Owner,或称为群主,充当服务端,并需要创建 ServerSocket 等待客户端的连接,获得 IO 流与客户端通讯或转发消息给其他客户端。

2、P2P Client,或称为组员,充当客户端,需要创建 Socket 与服务器通讯。

3、P2P Device,在上面的过程中,服务器端和客户端都是一个独立的设备,拥有唯一的设备特征信息。

4、广播接收器:

WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION:检查 Wi-Fi P2P 是否已启用。Android 4.0 以上系统才有此功能。

WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION:对等设备发生变化,一般是在调用 discoverPeers 方法后发送此广播。在此广播中,你可以调用 requestPeers 方法,获得扫描到的对等设备列表。

WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION:连接状态发生变化,一般在调用 connect 或 cancelConnect 方法时会发送此广播。状态共有 5 种:WifiP2pDevice.AVAILABLE、WifiP2pDevice.INVITED、WifiP2pDevice.CONNECTED、WifiP2pDevice.FAILED 和 WifiP2pDevice.UNAVAILABLE 。

当判断连接信息为连接状态时,即 networkInfo.isConnected() ,你应当继续请求连接的具体信息 mManager.requestConnectionInfo(...),然后获得群主的详细设备信息,建立 Socket 通讯。

WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION:此设备的WiFi状态更改回调,应用可使用 requestDeviceInfo() 来检索当前连接信息。

在未组网之前,是不存在群主、组员之称的。只有在设备尝试发现并连接对方时,系统才会通过 P2P 协议尝试使多端设备组件为一个群组,并自动确定某一个设备为群主。但是本人在实测过程中发现,是需要先有群主,才会加入组员组网通讯的。

更底层的原理参考:https://blog.csdn.net/wirelessdisplay/article/details/53365377

连接流程:

绘制了一张流程图,描述我 Demo 的连接过程。

服务端流程:

客户端流程:

Android 代码层面介绍:

1、设置相关权限:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />

因为在建立 P2P 连接后,需要建立 Socket 通讯,所以需要 INTERNET 权限。

2、注册广播,有 4 个核心广播 Action:

@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {// Check to see if Wi-Fi is enabled and notify appropriate activity// 检查 Wi-Fi P2P 是否已启用int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);boolean isEnabled = (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED);if (mWifiP2PListener != null) {mWifiP2PListener.onWifiP2pEnabled(isEnabled);}} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {// Call WifiP2pManager.requestPeers() to get a list of current peersWifiP2pDeviceList wifiP2pDeviceList = intent.getParcelableExtra(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);if (mWifiP2PListener != null && wifiP2pDeviceList != null) {mWifiP2PListener.onPeersAvailable(wifiP2pDeviceList.getDeviceList());}// 异步方法WifiP2PHelper.getInstance(context).requestPeers();} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {// Respond to new connection or disconnections// 链接状态变化回调// 此广播 会和 WIFI_P2P_THIS_DEVICE_CHANGED_ACTION 同时回调// 注册广播、连接成功、连接失败 三种时机都会调用// 应用可使用 requestConnectionInfo()、requestNetworkInfo() 或 requestGroupInfo() 来检索当前连接信息。NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);if (networkInfo != null&& networkInfo.isConnected()&& mManager != null&& mWifiP2PListener != null) {WifiP2PHelper.getInstance(context).requestConnectInfo();} else {if (mWifiP2PListener != null) {mWifiP2PListener.onConnectionInfoAvailable(null);}}} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {// Respond to this device's wifi state changing// 此设备的WiFi状态更改回调// 此广播 会和 WIFI_P2P_CONNECTION_CHANGED_ACTION 同时回调// 注册广播、连接成功、连接失败 三种时机都会调用// 应用可使用 requestDeviceInfo() 来检索当前连接信息。WifiP2pDevice wifiP2pDevice = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);if (mWifiP2PListener != null) {mWifiP2PListener.onSelfDeviceAvailable(wifiP2pDevice);}}}

3、初始化 Wifi P2P:

private WifiP2PHelper(Context context) {if (context == null || context.getApplicationContext() == null) {throw new IllegalArgumentException("context is null exception.");}mApplicationContext = context.getApplicationContext();mManager = (WifiP2pManager) mApplicationContext.getSystemService(Context.WIFI_P2P_SERVICE);// 将此应用注册到 WLAN P2P 框架mChannel = mManager.initialize(mApplicationContext, Looper.getMainLooper(), null);mReceiver = new WifiP2PBroadCastReceiver(mManager, mChannel);
}

初始化阶段的核心就是调用 manager.initialize(...) 方法,得到群组内通讯的通道对象 channel。

4、服务端创建群组:

public void createGroup() {mManager.createGroup(mChannel, new WifiP2pManager.ActionListener() {@Overridepublic void onSuccess() {if (mWifiP2PListener != null) {mWifiP2PListener.onCreateGroup(true);}}@Overridepublic void onFailure(int reason) {if (mWifiP2PListener != null) {mWifiP2PListener.onCreateGroup(false);}}});
}

5、客户端扫描对等设备:

public void discover() {mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {@Overridepublic void onSuccess() {if (mWifiP2PListener != null) {mWifiP2PListener.onDiscoverPeers(true);}}@Overridepublic void onFailure(int reason) {if (mWifiP2PListener != null) {mWifiP2PListener.onDiscoverPeers(false);}}});
}

6、客户端收到扫描成功广播后,请求扫描到的结果。尝试了解设备,获取到连接广播,在连接成功时,请求连接的详细信息,获取服务端的 IP 地址,建立 Socket 连接。

} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {// Call WifiP2pManager.requestPeers() to get a list of current peersWifiP2pDeviceList wifiP2pDeviceList = intent.getParcelableExtra(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);if (mWifiP2PListener != null && wifiP2pDeviceList != null) {mWifiP2PListener.onPeersAvailable(wifiP2pDeviceList.getDeviceList());}// 异步方法WifiP2PHelper.getInstance(context).requestPeers();} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {// Respond to new connection or disconnections// 链接状态变化回调// 此广播 会和 WIFI_P2P_THIS_DEVICE_CHANGED_ACTION 同时回调// 注册广播、连接成功、连接失败 三种时机都会调用// 应用可使用 requestConnectionInfo()、requestNetworkInfo() 或 requestGroupInfo() 来检索当前连接信息。NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);if (networkInfo != null&& networkInfo.isConnected()&& mManager != null&& mWifiP2PListener != null) {WifiP2PHelper.getInstance(context).requestConnectInfo();} else {if (mWifiP2PListener != null) {mWifiP2PListener.onConnectionInfoAvailable(null);}}} 

7、服务器创建 ServerSocket 接收客户端,并死循环读取 InputStream 数据:

private void initSocket() {try {serverSocket = new ServerSocket(SERVER_PORT);// 需要设置为无限超时
//            serverSocket.setSoTimeout(10000);while (!isQuitReadClient) {socket = serverSocket.accept();inputStream = socket.getInputStream();outputStream = socket.getOutputStream();String text = "连接到客户端 -> " + PHONE_INFO;IOHelper.writeText(outputStream, text);}} catch (Exception e) {e.printStackTrace();}}private void receive() {try {while (!isQuitReadMessage) {Thread.sleep(500);String text = IOHelper.readText(inputStream);if (TextUtils.isEmpty(text)) {continue;}postToUI(text);}} catch (Exception e) {e.printStackTrace();}}

8、客户端床架 Socket 连接服务端,并死循环读取 InputStream:

private void initSocket() {try {socket = new Socket(serverIP, SERVER_PORT);inputStream = socket.getInputStream();outputStream = socket.getOutputStream();String text = "连接到服务端 -> " + PHONE_INFO;IOHelper.writeText(outputStream, text);} catch (IOException e) {e.printStackTrace();}}private void receive() {try {while (!isQuitReadMessage) {Thread.sleep(500);String text = IOHelper.readText(inputStream);if (TextUtils.isEmpty(text)) {continue;}postToUI(text);}} catch (Exception e) {e.printStackTrace();}}

Demo 效果图:

服务端:

客户端:

服务端接收连接确认对话框:

坑点:

1、需要先创建群组,客户端才可以连接并加入组,否则连接不上。

2、服务端 ServerSocket 在等待时不要设置超时,否则遇到客户端连不上问题时难以排查。

3、如果服务端退出时没有移除群组,或客户端退出时没有断开连接,在下次连接时会出现连不上问题,不确定原因。

4、客户端首次连接服务端时,服务端会弹出请求对话框。服务端同意后才会建立连接。

Demo 下载地址:https://github.com/mengzhinan/WiFi_P2P_test

Android Wifi P2P 入门相关推荐

  1. android wifi p2p / wifi direct

    版权声明:本文为博主原创文章,未经博主允许不得转载.https://blog.csdn.net/h784707460/article/details/81502574 一. wifi P2P协议相关 ...

  2. android wifi p2p框架,7.2.1 P2P架构

    P2P架构中定义了三个组件,笔者将其称之为一个设备,两种角色.这三个组件分别是: * P2P Device:它是P2P架构中角色的实体,读者可把它当做一个Wi-Fi设备. * P2P Group Ow ...

  3. android wifi布局,Android使用 WiFi 建立 P2P 连接

    Wi-Fi 点对点(P2P)API 允许应用程序在无需连接到网络和热点的情况下连接到附近的设备.(Android Wi-Fi P2P 使用 Wi-Fi Direct™ 验证程序进行编译).Wi-Fi ...

  4. 【WLAN】Android 13 p2p / wifi direct介绍

    一. WifiP2pSettings和WifiP2pService介绍 WifiP2pSettings是Settings应用中负责处理P2P相关UI/UE逻辑的主要类,与之交互的则是位于SystemS ...

  5. android p2p 连接服务器上,当通过Wi-Fi P2P使用网络服务发现时无法连接到Android设备每个人都可以使用网络服务发现...

    ! 我正在开发一个Android应用程序,允许与附近已安装此应用程序的设备聊天.为了做到这一点,我使用Wi-Fi P2P API和网络服务发现来搜索附近的设备. 我已经编写了用于在服务启动的线程中搜索 ...

  6. 创建WIFI Direct APP : android.net.wifi.p2p+android.net.wifi.p2p.nsd + Wi-Fi peer-to-peer overview 翻译

    一 ) Provides classes to create peer-to-peer (P2P) connections with Wi-Fi Direct. 提供用于使用Wi-Fi Direct创 ...

  7. Android Wi-Fi子系统学习笔记

    一.学习目的 了解Android  Wi-Fi模组的移植及调试 二.基础知识 1.wifi的两个标志: (1)无线 (2)基于IEEE802.11协议 2.Android wifi模块的三个作用 (1 ...

  8. linux wifi开发书籍,Android WIFI开发介绍.pdf

    Android WIFI开发介绍: WifiStateTracker 会创建WifiMonitor 接收来自底层的事件,WifiService 和WifiMonitor 是整个模块的核心.WifiSe ...

  9. Android Wi-Fi Display(Miracast)介绍

    Android Wi-Fi Display(Miracast)介绍 2012年11月中旬,Google发布了Android 4.2.虽然它和Android 4.1同属Jelly Bean系列,但却添加 ...

最新文章

  1. 没听说过这些,就不要说你懂并发了,three。
  2. C#实现http断点下载
  3. 映射文件xxx.hbm.xml下的各元素结构
  4. 牛客一 G-Game of Swapping Numbers
  5. Python3需要安装的MySQL库是mysqlclient
  6. 四十六、MongoDB数据库学习
  7. python中多层装饰器使用步骤
  8. 前端vue实现pdf文件的在线预览
  9. 独辟蹊径,Python打造新型基于图像隐写术的C2通道
  10. POJ1067 取石子游戏 跪跪跪,很好的博弈论
  11. 工作 10 年,月薪过万者不足三成,程序员却笑了!
  12. 并发编程学习(2)----volatile与synchronized
  13. 如何正确地使用#region指令
  14. 嵌入式linux 中文输入法,一种用于嵌入式Linux系统的中文拼音输入法的制作方法...
  15. 3ds Max中的复制方式
  16. 如何搭建一个属于自己的博客网站?(小白教程)
  17. 我的世界java百度什么电脑玩好_【我的世界】为了在龙芯电脑上玩Minecraft(我的世界)我做了什么_玩得好游戏攻略...
  18. 局域网或外网Nexus私服下载安装仓库使用整理(Linux环境)这一篇足够
  19. Retrace AV推出新型涂料添加剂,可在30分钟内灭杀新冠病毒
  20. 教你几招亚马逊促销旺季爆单选品攻略技巧

热门文章

  1. C:\KEIL\C51\intrins.h包含不正确的路径。Keil 头文件路径错误
  2. iPhone5越狱后经典插件个人推荐
  3. NCBI RefSeq命名格式的详细说明
  4. android刷机知识大全,安卓主流机型刷机基础科普 教你刷机不求人
  5. 网管的自我修养-人际关系
  6. 从零开始,Latex + Vscode的安装和使用
  7. 室内施工图LiSP_CAD快速做室内设计图的技巧
  8. mysql被删库如何恢复_mysql整个数据库被删除了怎么恢复
  9. 高等数学——导数的定义和常见导数
  10. 【C#】线程之Parallel