android wifi直连 wifip2pmanager

android wifi直连 wifip2pmanager;使用WiFi 直连,然后通过udp进行通讯。
Android WiFi 直连(Wi-Fi Direct,也称为Wi-Fi P2P)是一种让两台或多台设备通过Wi-Fi技术直接进行点对点连接的技术,无需借助传统的无线路由器或接入点。这种技术使得设备间可以快速建立安全的无线连接,实现文件传输、屏幕共享、游戏对战等多种应用,尤其适用于智能手机、平板电脑、打印机、相机等消费电子设备间的近距离通信。

以下是Android WiFi 直连的基本工作原理和使用步骤:

工作原理:
设备发现:启用Wi-Fi Direct功能的设备可以通过广播信号搜索和发现附近的其他支持Wi-Fi Direct的设备。设备间可以互相检测到对方的存在,并显示在设备列表中供用户选择。

连接请求:用户在设备列表中选择要连接的目标设备后,发起连接请求。目标设备收到请求后,通常需要手动或自动确认接受连接。

组建立:一旦连接请求被接受,两台设备之间会自动建立一个Wi-Fi Direct组。在这个组中,一台设备会被选为“组主人”(Group Owner,GO),相当于小型网络的接入点,负责管理组内的连接和数据传输。另一台设备则作为“客户端”(Client)加入该组。

数据传输:连接建立后,组主人和客户端设备可以使用各自的IP地址和端口号进行直接的TCP/UDP通信。应用程序可以利用这些网络参数创建Socket连接,进行文件传输、消息传递等操作。

例子代码:

public class WifiConnectActivity extends AppCompatActivity {private Button btnConnect;private WifiDirectLink wifiDirectLink;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);LinearLayout linearLayout = new LinearLayout(this);linearLayout.setOrientation(LinearLayout.VERTICAL);setContentView(linearLayout);btnConnect = new AppCompatButton(this);btnConnect.setText("链接");AppCompatButton btnConnect2 = new AppCompatButton(this);btnConnect2.setText("发送");linearLayout.addView(btnConnect);linearLayout.addView(btnConnect2);wifiDirectLink = new WifiDirectLink(getApplicationContext());// 按钮点击事件 - 连接到对等设备btnConnect.setOnClickListener(v -> wifiDirectLink.connectToPeer());btnConnect2.setOnClickListener(v -> wifiDirectLink.send("hello".getBytes()));if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.NEARBY_WIFI_DEVICES}, 119);} else {ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 119);}}@Overrideprotected void onDestroy() {wifiDirectLink.release();super.onDestroy();}}

连接工具类:

import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pDeviceList;
import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;import androidx.core.content.ContextCompat;import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;public class WifiDirectLink {private static final String TAG = "WifiDirectLink";private final WifiP2pManager wifiP2pManager;private final WifiP2pManager.Channel channel;private Context context;private final Handler handler = new Handler(Looper.getMainLooper());private SyncUDP udp;private String otherClientIp;public WifiDirectLink(Context context) {this.context = context;Log.i(TAG, "WifiDirectLink: begin start-----------------------------------------------");if (udp == null) {udp = new SyncUDP(Config.BROADCAST_PORT + 3);udp.setListener(this::receiveAction);}// 初始化Wi-Fi P2P管理器和通道wifiP2pManager = (WifiP2pManager) context.getSystemService(Context.WIFI_P2P_SERVICE);channel = wifiP2pManager.initialize(context, Looper.getMainLooper(), null);// 创建意图过滤器并添加所需的意图动作IntentFilter intentFilter = new 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);// 注册广播接收器ContextCompat.registerReceiver(context, broadcastReceiver, intentFilter, ContextCompat.RECEIVER_EXPORTED);handler.postDelayed(new Runnable() {@Overridepublic void run() {try {discoverPeers();} catch (Exception e) {e.printStackTrace();}handler.postDelayed(this, 8888);}}, 88);}private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {Log.i(TAG, "onReceive: " + intent.getAction());String action = intent.getAction();if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {// 获取连接信息WifiP2pInfo wifiP2pInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO);if (wifiP2pInfo != null) {new Thread(() -> {// 获取groupOwnerAddressInetAddress groupOwnerAddress = wifiP2pInfo.groupOwnerAddress;// 在这里可以使用groupOwnerAddress进行相应的操作if (groupOwnerAddress != null) {String hostAddress = groupOwnerAddress.getHostAddress();String hostName = groupOwnerAddress.getHostName();byte[] address = groupOwnerAddress.getAddress();String canonicalHostName = groupOwnerAddress.getCanonicalHostName();Log.i(TAG, "onReceive: get host address:" + hostAddress + "; " + hostName + "; " + address + "; " + canonicalHostName);// start socket connectotherClientIp = hostAddress;if (!TextUtils.isEmpty(otherClientIp)) {new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(context.getApplicationContext(), "获取鬣主任ip", Toast.LENGTH_LONG).show());}}}).start();}}}};public void send(byte[] buf) {// 广播 都接受得到Log.i(TAG, "send: other client ip:" + otherClientIp);if (udp == null || otherClientIp == null) return;new Thread(() -> {String substring = otherClientIp.substring(0, otherClientIp.lastIndexOf("."));substring = substring + ".255";udp.sendAction(buf, substring);}).start();}@SuppressLint("MissingPermission")public void discoverPeers() throws Exception {wifiP2pManager.discoverPeers(channel, new WifiP2pManager.ActionListener() {@Overridepublic void onSuccess() {Log.i(TAG, "onSuccess: scan wifi node");}@Overridepublic void onFailure(int i) {Log.i(TAG, "onFailure: No nodes scanned");}});}@SuppressLint("MissingPermission")public void connectToPeer() {Log.i(TAG, "connectToPeer: start connect");wifiP2pManager.requestPeers(channel, wifiP2pDeviceList -> {List<WifiP2pDevice> deviceList = new ArrayList<>(wifiP2pDeviceList.getDeviceList());Log.i(TAG, "connectToPeer: item count:" + deviceList.size());if (deviceList.size() == 0) {return;}for (WifiP2pDevice item : deviceList) {Log.i(TAG, "connectToPeer: item name:" + item.deviceName + "; " + item.deviceAddress);// 创建连接配置WifiP2pConfig config = new WifiP2pConfig();config.deviceAddress = item.deviceAddress;connectItem(config, item);}});}@SuppressLint("MissingPermission")private void connectItem(WifiP2pConfig config, WifiP2pDevice item) {try {wifiP2pManager.connect(channel, config, new WifiP2pManager.ActionListener() {@Overridepublic void onSuccess() {Log.i(TAG, "onSuccess: Link successful for:" + item.deviceName + "; " + item.deviceAddress);}@Overridepublic void onFailure(int reasonCode) {Log.i(TAG, "onFailure: Link failure for:" + item.deviceName + "; " + item.deviceAddress);}});} catch (Exception e) {e.printStackTrace();Log.i(TAG, "getDevices: connect item error:" + e.getMessage());}}private void receiveAction(byte[] buffer, int len, String ip) {Log.i(TAG, "receiveAction: ip:" + ip + "; len:" + len);}public void release() {handler.removeCallbacksAndMessages(null);if (udp != null) {udp.release();udp = null;}try {context.unregisterReceiver(broadcastReceiver);} catch (Exception e) {e.printStackTrace();Log.i(TAG, "release: error:" + e.getMessage());}try {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) channel.close();} catch (Exception e) {e.printStackTrace();Log.i(TAG, "release:close channel error:" + e.getMessage());}}
}

udp 通讯类:

import android.util.Log;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;public class SyncUDP implements Runnable {private static final String TAG = "ReceiveUDP";private Thread thread;private DatagramSocket socket;private OnUpdateListener listener;private int port;public void setListener(OnUpdateListener listener) {this.listener = listener;}public void release() {if (thread != null && !thread.isInterrupted())thread.interrupt();listener = null;closeSocket();if (thread != null) {try {thread.join();} catch (Exception e) {e.printStackTrace();}thread = null;}}public SyncUDP(int port) {this.port = port;thread = new Thread(this);thread.start();}public void sendAction(byte[] buf, String ip) {if (socket == null || socket.isClosed()) return;try {DatagramPacket sendPacket = new DatagramPacket(buf, buf.length);sendPacket.setAddress(InetAddress.getByName(ip));sendPacket.setPort(port);socket.send(sendPacket);} catch (Exception e) {e.printStackTrace();Log.i(TAG, "sendAction: send package error:" + e.getMessage());}}@Overridepublic void run() {while (!Thread.interrupted()) {try {byte[] by = new byte[16];socket = new DatagramSocket(port);socket.setBroadcast(true);while (!Thread.interrupted()) {try {// receive dataDatagramPacket receivePacket = new DatagramPacket(by, by.length);Log.i(TAG, "run: start wait package");// Join threadsocket.receive(receivePacket);String ip = receivePacket.getAddress().getHostAddress();Log.i(TAG, "run: get package len:" + receivePacket.getLength() + "; ip:" + ip);if (listener != null)listener.onUpdateUI(receivePacket.getData(), receivePacket.getLength(), ip);} catch (Exception e) {e.printStackTrace();break;}}closeSocket();} catch (Exception e) {e.printStackTrace();}}closeSocket();}private void closeSocket() {if (socket != null) {if (!socket.isClosed()) {try {socket.close();} catch (Exception e) {e.printStackTrace();}}socket = null;}}public interface OnUpdateListener {void onUpdateUI(byte[] buffer, int len, String ip);}
}

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

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

相关文章

iOS知识点 ---- 离屏渲染

iOS 中的离屏渲染&#xff08;Off-Screen Rendering&#xff09;是指在绘制某些复杂图形或特殊效果时&#xff0c;系统无法直接在当前屏幕缓冲区进行绘制&#xff0c;而是需要先在额外的离屏缓冲区&#xff08;Off-Screen Buffer&#xff09;中完成渲染工作&#xff0c;然后再将…

electron打包编译国产统信uos系统 arm架构 x86架构 linux mac等环境

electron v21版本以上统信UOS会提示gbm_bo_map错误&#xff0c;可使用v8~v21版本的electron 打包linux包需要再linux系统下运行编译&#xff0c;arch可以指定架构 如果要在统信uos上运行&#xff0c;需要打包成deb格式&#xff0c;在target中修改成deb 或者用第三方软件把app…

three.js捋文档的记录笔记(六):场景 几何体 材质 物体 相机 渲染器的简单理解

三维场景Scene const scene new THREE.Scene();物体形状&#xff1a;几何体 Geometry //创建一个长方体几何对象Geometry const geometry new THREE.BoxGeometry(100, 100, 100); 物体外观&#xff1a;材质Material //创建一个材质对象Material const material new THREE.M…

在Vue3中如何使用H.265视频流媒体播放器EasyPlayer.js?

H5无插件流媒体播放器EasyPlayer属于一款高效、精炼、稳定且免费的流媒体播放器&#xff0c;可支持多种流媒体协议播放&#xff0c;可支持H.264与H.265编码格式&#xff0c;性能稳定、播放流畅&#xff0c;能支持WebSocket-FLV、HTTP-FLV&#xff0c;HLS&#xff08;m3u8&#…

【AIGC调研系列】Grok-1.5v与Gpt-4v的效果对比

Grok-1.5V与GPT-4V的效果对比中&#xff0c;Grok-1.5V在多个领域和基准测试中表现优于GPT-4V。具体来说&#xff0c;Grok-1.5V在多学科推理、文档理解、科学图表处理等方面表现出色[1]。它还特别强调了其在理解物理世界的能力上的优势[4][8][12]&#xff0c;并且在RealWorldQA基…

农作物数据分析

,表中文名,表英文名,字段中文名,字段英文名,字段类型,字段描述,字段权限,字段权限描述,字段权限类型 0,cropinfo,作物信息表,作物ID,cropid,UUIDField, 1,cropinfo,作物信息表,作物名称,cropname,CharField, 2,cropinfo,作物信息表,品种,variety,CharField, 3,cropinfo,作物信息…

C语言面试题之奇偶链表

奇偶链表 实例要求 1、给定单链表的头节点 head &#xff0c;将所有索引为奇数的节点和索引为偶数的节点分别组合在一起&#xff0c;然后返回重新排序的列表&#xff1b;2、第一个节点的索引被认为是 奇数 &#xff0c; 第二个节点的索引为 偶数 &#xff0c;以此类推&#x…

单链表接口函数的实现(增删查改)

一、单链表的实现形式以及接口函数的声明 #include<stdio.h> #include<stdlib.h> #include<assert.h> typedef int DataType ;typedef struct SListNode {DataType data;struct SListNode* next; }SLTNODE; void SLTPrint(SLTNODE* phead);//打印链表 SLTNO…

Wpf 使用 Prism 实战开发Day20

备忘录功能页面完善以及优化 备忘录功能基本跟前一章节的待办事项差不多一至&#xff0c;就不再做过多的笔述了 一.备忘录功能完整页面源码 MemoView.xaml <UserControl x:Class"MyToDo.Views.MemoView"xmlns"http://schemas.microsoft.com/winfx/2006/xam…

33、链表-排序链表

思路&#xff1a; 首先排序可以使用集合将所有节点放入集合中&#xff0c;然后再根据每个节点值进行排序。这个可以很容易做到&#xff0c;不再赘述 其次就是直接在链表上排序&#xff0c;如何排序可以使用归并排序的方式&#xff0c;代码如下&#xff1a; class Solution {…

opencv | 编译缺失ippicv相关文件解决方案

1.执行cmake后&#xff0c;查看控制台输出信息 ~/VM_data/opencv-4.9.0$ cd buile_temp ~/VM_data/opencv-4.9.0/buile_temp$ cmake ..2.去浏览器打开链接&#xff0c;下载对应的压缩包&#xff0c;解压到 路径&#xff1a;/3rdparty/ippicv/

CSS3 animation-delay 属性

CSS3 animation-delay 属性 实例 等待两秒&#xff0c;然后开始动画&#xff1a; animation-delay:2s; -webkit-animation-delay:2s; /* Safari 和 Chrome */标签定义及使用说明 animation-delay 属性定义动画什么时候开始。 animation-delay 值单位可以是秒&#xff08;s&…

Java多线程(一些常用方法

今天学了一点多线程&#xff0c;感觉有点乱乱的 一.有三种方法可以实现多线程 1.继承Thread类&#xff1b; 直接继承Thread类&#xff0c;重写run方法 package a0415; //第一种执行方法&#xff08;继承Thread类的方法进行实现&#xff09; public class Test1 {public sta…

​LeetCode解法汇总2924. 找到冠军 II

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 一场比赛中共有 n 支队伍&#xff0c;按从…

【云计算】安全组和网络ACL的区别

安全组和网络ACL的区别 ACL&#xff08;Access Control List&#xff09;和 安全组&#xff08;Security Group&#xff09;是两种不同的网络安全控制机制&#xff0c;通常用于管理云计算平台中的网络访问权限。它们在功能和实现上有一些显著的区别&#xff1a; 辨析 范围不同&…

数据库-Redis(16)

目录 76.新的主库选择出来后,如何进行故障的转移? 77.Redis事件机制? 78.Redis文件事件的模型? 79.什么是Redis发布订阅?

ASP.NET MVC企业级程序设计 (EF+三层架构+MVP实现查询数据)

目录 效果图 实现过程 1创建数据库 2创建项目文件 3创建控制器&#xff0c;右键添加&#xff0c;控制器 ​编辑 注意这里要写Home​编辑 创建成功 数据模型创建过程之前作品有具体过程​编辑 4创建DAL 5创建BLL 6创建视图&#xff0c;右键添加视图 ​编辑 7HomeContr…

【zookeeper】安装

第二次安装zookeeper了&#xff0c;蛮记录一下&#xff08;让blog丰富一点~&#xff09; 1. Apache Zookeeper官网下载 2. 解压后创建log和data文件夹 这个其实不一定要建在zookeeper文件夹下&#xff0c;建在任意一个文件夹里都行&#xff0c;只要配置文件中的路径配置能找到…

Spark面试整理-Spark部署和集群管理

Apache Spark的部署和集群管理是Spark应用的关键组成部分,它决定了如何在分布式环境中运行和管理Spark作业。Spark支持多种部署模式和集群管理器,以适应不同的需求和环境。以下是Spark部署和集群管理的主要方面: 部署模式 本地模式:在单个机器上运行Spark。适用于开发和测试…

软件设计不是CRUD(18):像搭积木一样搭建应用系统(上)——单个应用系统的搭建过程

1、概述 之前的文章本专题花了大量文字篇幅,介绍如何基于业务抽象的设计方式完成应用系统各个功能模块的设计工作。而之所以进行这样的功能模块设计无非是希望这些功能模块在具体的项目实施过程中,能够按照当时的需求快速的、简易的、稳定的、最大可能节约开发成本的形成可用…