WiFi P2P技术
WiFi P2P(Peer-to-Peer),也被称为WiFi Direct,是WiFi联盟发布的一个协议。允许无线网络中的设备在无需无线路由器的情况下相互连接,通过WiFi直接实现两台设备之间的无线点对点通信。原理与基于AP(接入点)的通信方式类似,支持P2P的设备可以在同一个小组内互传数据,实现同屏功能。
WiFi P2P被广泛应用于移动设备之间的文件共享、游戏联机、音乐播放等应用场景中。相较于蓝牙,WiFi P2P具有更快的搜索速度和传输速度,以及更远的传输距离。而且只需要打开WiFi即可,不需要加入任何网络或AP,即可实现对等点连接通讯。对于需要在用户之间共享数据的应用,如多人游戏或照片共享非常有用。
WiFi P2P也存在一些安全性问题,如用户隐私泄露、恶意软件和病毒传播,以及侵权和违法内容的传播。为了保护用户的安全和隐私,一些P2P网络提供了匿名化处理功能,使用安全搜索引擎,以及设置过滤器来阻止违法和侵权内容的共享。
Android WiFi P2P架构
在P2P架构中,定义了两种主要角色:P2P Group Owner(简称GO)和P2P Client(简称GC)。GO的作用类似于Infrastructure BSS中的AP(接入点),而GC的作用类似于Infrastructure BSS中的STA(站点)。当两台设备通过P2P连接后,会随机(也可以手动指定)指派其中一台设备为组拥有者(GO),相当于一台服务器,另一台设备为组成员(GC)。其他设备可以通过与GO设备连接加入组,但不能直接和GC设备连接。
在Android系统中,WiFi P2P功能是在Android 4.0及更高版本系统中加入的。它可以通过WifiP2pManager类进行实现,这个类提供了许多方法来扫描可用设备、建立P2P连接并传输数据等功能。开发者可以通过这些方法来实现设备之间的文件传输等操作。
在设备发现阶段,Android WiFi P2P使用Probe Request和Probe Response帧来交换设备信息。在2.4GHz的1、6、11频段上发送Probe Request帧,这几个频段被称为Social Channels。一旦Listen Channel选择好后,在整个P2P Discovery阶段就不能更改,用于快速发现周围的Group。
尽管Android WiFi P2P功能强大,目前在Android系统中只是内置了设备的搜索和链接功能,并没有像蓝牙那样有许多应用。在实际开发中,可能需要通过软件手段解决一些逻辑和权限问题。
Android应用WiFi P2P实现数据传输
在Android中,WiFi P2P可以通过WifiP2pManager类进行实现。开发者可以通过获取WifiP2pManager实例,并进行广播接受者的创建和注册,调用其他WiFi P2P的API,实现设备间的搜索、连接和数据传输等功能。例如,指定某一台设备为服务器,创建群组并等待客户端的连接请求,而客户端则可以主动搜索附近的设备并加入群组,向服务器发起文件传输请求。
添加权限
获取WifiP2pManager和WifiP2pManager.Channel对象
mWifiP2pManager = getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManagermWifiP2pManager?.initialize(this, Looper.getMainLooper()) {Log.d(TAG, "Channel断开连接")}
服务端创建群组
//服务端创建群组mWifiP2pManager?.createGroup(mChannel, object : WifiP2pManager.ActionListener {override fun onSuccess() {Log.d(TAG, "创建群组成功")}override fun onFailure(reason: Int) {Log.w(TAG, "创建群组失败$reason")}})
客户端搜索对等设备
//客户端搜索对等设备mWifiP2pManager?.discoverPeers(mChannel, object : WifiP2pManager.ActionListener {override fun onSuccess() {Log.d(TAG, "搜索成功")}override fun onFailure(reason: Int) {Log.d(TAG, "搜索失败:$reason")}})//使用异步方法(推荐通过广播监听) 获取设备列表mWifiP2pManager?.requestPeers(mChannel) {mDeviceList.addAll(it.deviceList)if (mDeviceList.isEmpty()) {//没有设备runOnUiThread { Toast.makeText(this, "没有发现设备", Toast.LENGTH_SHORT).show() }} else {//刷新列表runOnUiThread { mDeviceAdapter.notifyDataSetChanged() }}}
连接设备
val config = WifiP2pConfig().apply {this.deviceAddress = wifiP2pDevice.deviceAddressthis.wps.setup = WpsInfo.PBC}mWifiP2pManager?.connect(mChannel, config, object : WifiP2pManager.ActionListener {override fun onSuccess() {Log.d(TAG, "连接成功")}override fun onFailure(reason: Int) {Log.w(TAG, "连接失败$reason")}})
服务端创建Socket进行数据读写
// 将数据发送给客户端//需要创建子线程 否则在主线程网络操作直接闪退val serverSocket = ServerSocket(8888)val socket = serverSocket.accept()val inputStream = socket.getInputStream()val outputStream = socket.getOutputStream()//发送数据outputStream?.write(data)//此处为了方便 实际需要开启线程读取 并且要有合适的延迟while (!mQuitReadData) {val reader = inputStream.bufferedReader(StandardCharsets.UTF_8)val text = reader.readLine()Log.d(TAG, "读取到的数据$text")}
客户端创建Socket进行数据读写
//需要创建子线程 否则在主线程网络操作直接闪退val address: InetAddress = info.groupOwnerAddressval socket = Socket(address, 8888)val inputStream = socket.getInputStream()val outputStream = socket.getOutputStream()//发送数据outputStream?.write(data)//此处为了方便 实际需要开启线程读取 并且要有合适的延迟while (!mQuitReadData) {val reader = inputStream.bufferedReader(StandardCharsets.UTF_8)val text = reader.readLine()Log.d(TAG, "读取到的数据$text")}
class MainActivity : AppCompatActivity() {private val TAG = MainActivity::class.java.simpleNameprivate lateinit var mBinding: ActivityMainBindingprivate var mWifiP2pManager: WifiP2pManager? = nullprivate var mChannel: WifiP2pManager.Channel? = nullprivate var mDeviceList = arrayListOf<WifiP2pDevice>()private lateinit var mDeviceAdapter: DeviceAdapterprivate var mQuitReadData = true@SuppressLint("NotifyDataSetChanged")override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)enableEdgeToEdge()mBinding = ActivityMainBinding.inflate(layoutInflater)setContentView(mBinding.root)ViewCompat.setOnApplyWindowInsetsListener(mBinding.main) { v, insets ->val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)insets}val intentFilter = IntentFilter()intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION)registerReceiver(mReceiver, intentFilter)mDeviceAdapter = DeviceAdapter(mDeviceList)mBinding.rvDeviceList.adapter = mDeviceAdaptermDeviceAdapter.mOnItemSelectedListener = object : OnItemSelectedListener {override fun onItemSelected(parent: AdapterView<*>?,view: View?,position: Int,id: Long) {val wifiP2pDevice = mDeviceList[position]connect(wifiP2pDevice)}override fun onNothingSelected(parent: AdapterView<*>?) {}}//通用步骤mWifiP2pManager = getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManagermChannel = mWifiP2pManager?.initialize(this, Looper.getMainLooper()) {Log.d(TAG, "Channel断开连接")}//服务端部分//服务端创建群组mWifiP2pManager?.createGroup(mChannel, object : WifiP2pManager.ActionListener {override fun onSuccess() {Log.d(TAG, "创建群组成功")}override fun onFailure(reason: Int) {Log.w(TAG, "创建群组失败$reason")}})//客户端部分//客户端搜索对等设备mWifiP2pManager?.discoverPeers(mChannel, object : WifiP2pManager.ActionListener {override fun onSuccess() {Log.d(TAG, "搜索成功")}override fun onFailure(reason: Int) {Log.d(TAG, "搜索失败:$reason")}})//使用异步方法(推荐通过广播监听) 获取设备列表mWifiP2pManager?.requestPeers(mChannel) {mDeviceList.addAll(it.deviceList)if (mDeviceList.isEmpty()) {//没有设备runOnUiThread { Toast.makeText(this, "没有发现设备", Toast.LENGTH_SHORT).show() }} else {//刷新列表runOnUiThread { mDeviceAdapter.notifyDataSetChanged() }}}}/*** 连接设备*/private fun connect(wifiP2pDevice: WifiP2pDevice) {val config = WifiP2pConfig().apply {this.deviceAddress = wifiP2pDevice.deviceAddressthis.wps.setup = WpsInfo.PBC}mWifiP2pManager?.connect(mChannel, config, object : WifiP2pManager.ActionListener {override fun onSuccess() {Log.d(TAG, "连接成功")mQuitReadData = falsetransferData("Hello".toByteArray())}override fun onFailure(reason: Int) {Log.w(TAG, "连接失败$reason")mQuitReadData = true}})}private fun transferData(data: ByteArray) {//请求设备连接信息mWifiP2pManager?.requestConnectionInfo(mChannel) { info ->if (info.groupFormed && info.isGroupOwner) {// 将数据发送给客户端val serverSocket = ServerSocket(8888)val socket = serverSocket.accept()val inputStream = socket.getInputStream()val outputStream = socket.getOutputStream()//发送数据outputStream?.write(data)//此处为了方便 实际需要开启线程读取 并且要有合适的延迟while (!mQuitReadData) {val reader = inputStream.bufferedReader(StandardCharsets.UTF_8)val text = reader.readLine()Log.d(TAG, "读取到的数据$text")}} else {//设备是客户端val address: InetAddress = info.groupOwnerAddressval socket = Socket(address, 8888)val inputStream = socket.getInputStream()val outputStream = socket.getOutputStream()//发送数据outputStream?.write(data)//此处为了方便 实际需要开启线程读取 并且要有合适的延迟while (!mQuitReadData) {val reader = inputStream.bufferedReader(StandardCharsets.UTF_8)val text = reader.readLine()Log.d(TAG, "读取到的数据$text")}}}}private val mReceiver = object : BroadcastReceiver() {override fun onReceive(context: Context?, intent: Intent?) {val action = intent?.action;if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {// Check to see if Wi-Fi is enabled and notify appropriate activity// 检查 Wi-Fi P2P 是否已启用val state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1)val isEnabled = (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED)} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {// Call WifiP2pManager.requestPeers() to get a list of current peers//异步方法// mWifiP2pManager?.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() 来检索当前连接信息。} 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() 来检索当前连接信息。}}}override fun onDestroy() {super.onDestroy()//移除群组mWifiP2pManager?.removeGroup(mChannel, null)//取消链接mWifiP2pManager?.cancelConnect(mChannel, null)}}
Android WiFi P2P使用流程总结:
在AndroidManifest.xml中声明必要的权限,包括网络访问权限和文件读写权限。
在Android应用中,首先需要获取WifiP2pManager实例,并通过调用其initialize方法进行初始化。这将注册应用并准备使用Wi-Fi P2P功能。
初始化完成后,会获得一个Channel对象,它是后续操作的关键。
3.「广播接收与处理」:
在整个过程中,应用需要注册并监听特定的广播,以处理Wi-Fi P2P状态变化、设备发现、连接变化等事件。
这些广播会通知应用有关Wi-Fi P2P操作的状态和结果,以便应用可以做出相应的响应。
4.「设备发现」:
使用WifiP2pManager的discoverPeers方法开始搜索附近的Wi-Fi P2P设备。
设备会在特定的频段(如2.4GHz的1、6、11频段)上发送Probe Request帧来寻找其他设备。
搜索到的设备会作为列表展示在应用界面上,用户可以从中选择想要连接的设备。
5.「建立连接」:
选定一个设备后,作为客户端或服务端(Group Owner,GO)发起连接请求。
通过WifiP2pConfig对象配置连接参数,如目标设备的地址和WPS(Wi-Fi Protected Setup)设置。
使用WifiP2pManager的connect方法尝试建立连接。
6.「连接确认与数据传输」:
一旦连接建立成功,设备之间就可以开始数据传输了。
可以通过Socket编程在设备之间建立连接,并传输文件或其他数据。
根据应用需求,可以创建服务端套接字监听客户端的连接请求,也可以作为客户端主动连接到服务端。
7.「数据传输完成与断开连接」:
数据传输完成后,应用需要适当地关闭套接字和断开Wi-Fi P2P连接。
使用WifiP2pManager的相关方法来断开连接,并释放相关资源。
本网站的文章部分内容可能来源于网络和网友发布,仅供大家学习与参考,如有侵权,请联系站长进行删除处理,不代表本网站立场,转载者并注明出处:https://www.jmbhsh.com/baihuo725/35067.html