点对点传输(P2P)又是WLAN直连,他可以在没有中间接入点的情况下,通过 WLAN 进行直接互联。他有用户介入操作少,比蓝牙传输速度高等特点,对设备的要求仅仅为14,同时他又不占用wlan0网卡。

WLAN P2P 需要使用到 WifiP2pManager ,同时需要以下权限,这里面有一些是运行时权限,需要用户同意后才能使用。

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

点对点传输(P2P)至少有两个有Wifi的设备,其中一个是Android,首先确定Android设备和另外一个设备是否支持P2P连接。把手机连接电脑运行 adb shell ip addr|grep p2p0 -A2有输出就带边可以使用,一般来说都可以使用。

29: p2p0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc mq state DOWN group default qlen 1000link/ether 02:00:2d:63:a5:6b brd ff:ff:ff:ff:ff:ff

注意看上面的输出,link/ether 02:00:2d:63:a5:6 为p2p的Mac地址,不同的设备之间使用Mac地址连接,所以首先要知道P2P(p2p0)的Mac地址,这个和wifi(wlan0)的地址不是同一个,在代码中需要使用下面方法获取。

public static String getLocalMacAddress() {try {List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());for (NetworkInterface ntwInterface : interfaces) {if (ntwInterface.getName().equalsIgnoreCase("p2p0")) {byte[] byteMac = ntwInterface.getHardwareAddress();if (byteMac == null) {return null;}StringBuilder strBuilder = new StringBuilder();for (int i = 0; i < byteMac.length; i++) {strBuilder.append(String.format("%02X:", byteMac[i]));}if (strBuilder.length() > 0) {strBuilder.deleteCharAt(strBuilder.length() - 1);}return strBuilder.toString();}}} catch (Exception e) {Log.d("Lecon", e.getMessage());}return null;
}

接下来看一下如何主动连接到p2p设备。

使用方法

首先通过 WifiP2pManager 的initialize初始化。

val manager: WifiP2pManager? by lazy(LazyThreadSafetyMode.NONE) {getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager?
}override fun onCreate(savedInstanceState: Bundle?) {mChannel = manager?.initialize(this, mainLooper, null)
}

同时使用广播来接受各种P2P连接的状态变化。

var mChannel: WifiP2pManager.Channel? = null
var mReceiver: WiFiDirectBroadcastReceiver? = nullprivate val mWifiP2pManager: WifiP2pManager by lazy(LazyThreadSafetyMode.NONE) {getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager
}private val mIntentFilter: IntentFilter by lazy(LazyThreadSafetyMode.NONE) {IntentFilter().apply {addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION)}
}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)mChannel = mWifiP2pManager.initialize(this, mainLooper, null)mReceiver = WiFiDirectBroadcastReceiver(mWifiP2pManager, mChannel, this)
class WiFiDirectBroadcastReceiver(private val mManager: WifiP2pManager?,private val mChannel: WifiP2pManager.Channel?,private val mActivity: MainActivity
) : BroadcastReceiver() {override fun onReceive(context: Context, intent: Intent) {val action = intent.actionif (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION == action) {// 当 WLAN P2P 在设备上启用或停用时广播} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION == action) {// 调用 requestPeers() 方法,以获得当前所发现对等设备的列表。// 同时 在这里调用 connect 方法连接对方机器} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION == action) {// 当设备的 WLAN 连接状态更改时广播。// 连接对方机器成功或者失败都会在这里回调} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION == action) {// 当设备的详细信息(例如设备名称)更改时广播}
}

上边哪一些代码可以当成主动发起扫描之后的回调,使用广播进行回调说起来真的是挺复杂的,但是仔细想想,操作硬件设备本来就是跨进程的,而且这个还是长时间耗时操作,系统通过广播回调也是合理的。

到现在位置,可以把以上代码运行到Android上,他就可以最为P2P连接的被连接端。

连接到设备

连接到设备的时候,首先要确定对方设备的mac地址,上面的两种方法是针对于Android设备的。一种是adb方式,一种是代码获取。

接下来要发现设备:

mWifiP2pManager.discoverPeers(mChannel, object : WifiP2pManager.ActionListener {override fun onSuccess() {Toast.makeText(this@MainActivity, "已发现设备,准备连接", Toast.LENGTH_SHORT).show()}override fun onFailure(reasonCode: Int) {}
})

返现设备之后,通过广播回调的 WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION 事件获取设备列表。找到列表中的设备与被连接设备mac地址一致的,确保我们被连接机器已经就绪。

mManager?.requestPeers(mChannel) { peers ->for (device in peers.deviceList) {if (mac != null && mac.equals(device.deviceAddress, ignoreCase = true)) {connectToDevice(device)}}
}

接下来就可以连接设备了!

val config = WifiP2pConfig()
config.deviceAddress = "被连接设备的Mac地址"
mManager?.connect(mChannel, config, object : WifiP2pManager.ActionListener {override fun onSuccess() {Toast.makeText(mActivity, "连接成功", Toast.LENGTH_SHORT).show()}override fun onFailure(reason: Int) {}
})

如果被连接设备是Android,你应该能看到一个连接提示,点击接受这样两台设备之间就连接成功了,通过WIFI两个设备可以实现近场通讯。

通信

通信之前需要知道被连接设备的ip地址。如果是android设备,在被连接设备执行adb shell ip addr|grep p2p0 -A4 就可以看到,这也是检测是否连接成功的方法。代码获取仍然要获取p2p0网卡的,wlan0获取的ip地址不能用于这里。

public static String getLocalIp() {try {List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());for (NetworkInterface intf : interfaces) {if (!intf.getName().contains("p2p0"))continue;List<InetAddress> addrs = Collections.list(intf.getInetAddresses());for (InetAddress addr : addrs) {if (!addr.isLoopbackAddress()) {return addr.getHostAddress().toUpperCase();}}}} catch (Exception ex) {ex.printStackTrace();}return "";
}

如果被连接设备是一台服务器(在Android里面搭建一台服务器也是可以的),在这台设备上可以用okhttp等框架进行网络访问,或者使用socket进行传输。
现在两个手机(P2P)设备之间就可以同过WLAN直接通信了。

下面是源代码:https://github.com/leconio/WifiDircetP2PDemo

Android 设备通过WIFI传输数据 - 点对点传输相关推荐

  1. 获取Android 设备的WIFI IPv4地址

    一.前言 有时候需要获取Android设备的IPv4地址,可以通过下面列出的一种方法获取. 二.获取方法 // 获取IPv4地址private String getDeviceIPv4() {//获取 ...

  2. 使用iperfjperf测试Android设备的wifi速率方法

    测试设备:PC电脑,路由器,安卓设备 测试工具软件:iperf和jperf 测试方法使用到两个软件:jperf实际为iperf的图形化程序,因为使用到PC,所以用jperf比较方便.而Android设 ...

  3. android设备获取wifi和蓝牙状态并进行打开或关闭操作

    wifi 获取系统wifi服务: WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Co ...

  4. 通过wifi连接android设备的方法

    最近由于要在另外一台android设备上调试代码,在本机PC上查看其log.两台机器离的比较远, 无法用usb直接连接,于是在网上找了很多资料,最找使用adb connect方法解决了该问题.解决过程 ...

  5. adb通过wifi连接android设备(魅族note3)

    AS使用usb数据线调试手机时有时一松碰一下就断了,所以尝试用无线调试会稳定一点. 1.首先安装ADB WIFI 打开FILE->Settings->Plugins->Browse ...

  6. esc pos命令 java使用_18、ESC/POS指令集在android设备上使用实例(通过socket)

    网上关于通过android来操作打印机的例子太少了,为了方便更多的开发同仁,将近日所学分享一下. 我这边是通过android设备通过无线来对打印机(佳博58mm热敏式-58130iC)操作,实现餐厅小 ...

  7. Android手机用wifi连接adb调试的方法

    https://www.jianshu.com/p/dc6898380e38 0x0 前言 Android开发肯定要连接pc的adb进行调试,传统的方法是用usb与pc进行连接,操作简单即插即用,缺点 ...

  8. Android 9.0 WiFi BG Scan机制

    欢迎大家一起学习探讨通信之WLAN.本节我们讨论关于Android设备的WiFi Background 扫描机制.通过使用WiFi设备的经验可知.WiFi设备连接上WiFi网络,必要条件是需要扫描到目 ...

  9. 连接android设备

    一,WIFI连接 1,将android设备接入wifi 2,查看设备IP:设置-->无线和网络-->WLAN-->WLAN设置(在右上角)-->IP地址 :192.168.13 ...

最新文章

  1. 基于redis AE异步网络架构
  2. 离线轻量级大数据平台Spark之MLib机器学习库Word2Vec实例
  3. Lighting System Design UVA - 11400 动态规划
  4. php表单写入数据库,php表单写入数据库
  5. 授人以鱼不如授人以渔——CPU漏洞的Symantec解决之道
  6. vscode 使用笔记
  7. Self Attention和Multi-Head Attention的原理和实现
  8. [HTTP] HTTP各种特性总览
  9. 适用于 Windows PowerShell 的 SMS Cmdlet
  10. BootStrap的基本使用
  11. 计算机安装重装出现错误,一键重装失败怎么办?电脑重装系统失败的原因和解决方法...
  12. MAC IDEA常用快捷键
  13. 错误 E: Could not get lock /var/lib/dpkg/lock-frontend - open (11: Resource temporarily unavailable)
  14. 之前用Delphi随手写的软键盘SoftKeyBoard
  15. windows替换鼠标指针
  16. C语言实现创建游戏角色(包含文件写入)
  17. 【开始报名】第二届中国移动“梧桐杯”大数据应用创新大赛邀你夺52w大奖
  18. 马克思 第一章 世界的物质性及其发展规律
  19. Python+selenium+360浏览器实现自动测试
  20. UI基础三:简单的BOL报表开发

热门文章

  1. 看图猜成语小程序源码
  2. 数字高程模型的提出、演变、重要性及定义
  3. 仙之侠道2玖章各个任务详情_仙之侠道2玖章任务地点 | 手游网游页游攻略大全...
  4. 织梦DEDE三级栏目导航实现 亲测有效
  5. 领带的10种打法(男人必看)
  6. Android——UIL实现图片缓存基本配置及使用
  7. COMX51 基于 STM32 实现 PROFINET 从站开发
  8. 如何分析公众号后台数据?
  9. 制作可以随身携带的系统盘
  10. 命令强制卸载IE方法