Android WiFi直连 双向通信
原文地址:https://blog.csdn.net/VNanyesheshou/article/details/82316436
一、准备工作
开发环境:
jdk1.8
AS(3.0.1)
运行环境:
华为V10(Android8.0)、HTC(Android7.0)
实现功能:
Android WiFi直连 ,扫描、连接、双向传输图片,显示图片
二、代码结构与运行效果
代码结构图

运行效果图

三、代码详解
本文主要说一下,Android通过WiFi直连的方式实现图片双向传输(图片可以传输,也可以把它修改下传输聊天信息了)。
1 WiFi直连概述
WiFi直连也就是WiFi设备点对点连接(WiFi P2P),它允许具有适当硬件的Android 4.0(API级别14)或更高版本的设备通过Wi-Fi直接相互连接,而无需中间接入点。使用这些API,您可以发现并连接到其他设备(前提是每个设备支持Wi-Fi P2P),然后通过比蓝牙连接更长的距离快速连接进行通信。这对于在用户之间共享数据的应用程序很有用,例如多人游戏或照片共享应用程序。
Wi-Fi P2P API包含以下主要部分:
允许您发现,请求和连接到对等的方法在WifiP2pManager类中定义。
允许您通知WifiP2pManager方法调用成功或失败的监听器。调用WifiP2pManager方法时,每个方法都可以接收作为参数传入的特定侦听器。
通知您Wi-Fi P2P框架检测到的特定事件的意图,例如断开的连接或新发现的对等体。
您经常将API的这三个主要组件一起使用。例如,您可以提供WifiP2pManager.ActionListener呼叫discoverPeers(),以便您可以使用ActionListener.onSuccess()和ActionListener.onFailure() 方法通知您。
2 Demo

注意事项:
2.1 搜索不到可用设备
- 确保对端设备处于搜索状态;
- 对端设备异常,可尝试重启WLAN开关,重新搜索。
- 自身设备异常,可尝试重启WLAN开关,重新搜索。
2.2 连接失败
- 确保对端设备没有与其他设备建立WLAN直连连接。
- 确保对端设备接收连接请求。
- 对端设备异常,请尝试重新连接。
3 创建Wi-Fi P2P应用程序
创建Wi-Fi P2P应用程序涉及为您的应用程序创建和注册广播接收器,发现对等体,连接到对等体以及将数据传输到对等体。以下部分描述了如何执行此操作。
3.1 初始设置
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.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-feature android:name="android.hardware.wifi.direct" android:required="true"/>
build.gradle并设置最小版本为14或以上。 minSdkVersion 14
2 初始化
获取Wi-Fi P2P框架的实例并注册您的应用程序。
//获取Wifi P2P服务对象
mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
// 注册应用程序 这一步必须的。
mChannel = mWifiP2pManager.initialize(this, getMainLooper(), null);
3 注册监听
IntentFilter intentFilter = new IntentFilter();
//监听 Wi-Fi P2P是否开启
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
//监听 Wi-Fi P2P扫描状态
intentFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION);
//监听 可用的P2P列表发生了改变。
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
//监听 Wi-Fi P2P的连接状态发生了改变
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
//监听 设备的详细配置发生了变化
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
mReceiver = new WiFiDirectBroadcastReceiver(mWifiP2pManager, mChannel, this);
//对上述的action 进行注册监听
registerReceiver(mReceiver, intentFilter);
3.2 发现设备
调用discoverPeers()以检测范围内的可用对等方,此函数的调用是异步的。如果您创建了一个WifiP2pManager.ActionListener,则会将成功或失败传递给您的应用程序onSuccess(),onFailure()。该 onSuccess()方法仅通知您发现过程成功,并且未提供有关其发现的实际对等方的任何信息
mWifiP2pManager.discoverPeers(mChannel, new ActionListener() {
//启动成功,实际上还没有发现任何服务,因此这种方法通常可以留空。
@Override
public void onSuccess() {
Toast.makeText(MainActivity.this, "Discovery Initiated",
Toast.LENGTH_SHORT).show();
}
//启动失败
@Override
public void onFailure(int reasonCode) {
Toast.makeText(MainActivity.this, "Discovery Failed : " + reasonCode,
Toast.LENGTH_SHORT).show();
}
});
如果发现过程成功并检测到对等体,则系统会发送广播WIFI_P2P_PEERS_CHANGED_ACTION,您可以在广播接收器中监听该意图以获得对等体列表。当您的应用程序收到WIFI_P2P_PEERS_CHANGED_ACTION意图时,您可以请求已发现的对等方的列表requestPeers()。以下代码显示了如何设置它:
PeerListListener peerListListener;
if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
// request available peers from the wifi p2p manager. This is an
// asynchronous call and the calling activity is notified with a
// callback on PeerListListener.onPeersAvailable()
if (mManager != null) {
mManager.requestPeers(mChannel, peerListListener);
}
}
该requestPeers()方法也是异步的,并且可以在对等列表可用时通知您的活动,该列表onPeersAvailable()在WifiP2pManager.PeerListListener接口中定义。该onPeersAvailable()方法为您提供了一个WifiP2pDeviceList,您可以迭代以查找要连接的对等方。
3.3 连接
在获取可用的对等项列表后,如果已找到要连接的设备,请调用该connect()方法以连接到该设备。此方法调用需要一个WifiP2pConfig 包含要连接的设备信息的对象。以下代码显示如何创建与所需设备的连接:
WifiP2pDevice device;
WifiP2pConfig config = new WifiP2pConfig();
//设置地址
config.deviceAddress = device.deviceAddress;
mManager.connect(mChannel, config, new ActionListener() {
@Override
public void onSuccess() {
}
@Override
public void onFailure(int reason) {
//failure logic
}
});
WifiP2pManager.ActionListener中onSuccess()并不能表示成功连接,而是应该通过广播监听
ConnectionInfoListener infoListener
if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
NetworkInfo networkInfo = (NetworkInfo) intent
.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
if (networkInfo.isConnected()) {
// we are connected with the other device, request connection
// info to find group owner IP
manager.requestConnectionInfo(channel, infoListener);
} else {
// It's a disconnect
}
}
连接成功后,调用requestConnectionInfo()获取group的相关信息。该操作是异步的,在如下代码涨接收信息:
@Override
public void onConnectionInfoAvailable(final WifiP2pInfo info) {
if (info.groupFormed && info.isGroupOwner) {
//server 创建ServerSocket
} else if (info.groupFormed) {
// The other device acts as the client. In this case, we enable the
// get file button.
//连接Server。
}
}
3.4 Socket
建立连接后,您可以使用套接字在设备之间传输数据。传输数据的基本步骤如下:
创建一个ServerSocket。此套接字等待来自指定端口上的客户端的连接并阻塞直到它发生,因此在后台线程中执行此操作。
创建一个客户端Socket。客户端使用服务器套接字的IP地址和端口连接到服务器设备。
将数据从客户端发送到服务器。当客户端套接字成功连接到服务器套接字时,您可以使用字节流将数据从客户端发送到服务,也可以从服务端发送到客户端。
服务器套接字等待客户端连接(使用该accept()方法)。此调用将阻塞,直到客户端连接,因此调用它是另一个线程。当连接发生时,服务器设备可以从客户端接收数据。对此数据执行任何操作,例如将其保存到文件或将其呈现给用户。
group owner创建Server Socket,等待连接
mServerSocket = new ServerSocket(SOCKET_PORT);
mClientSocket = mServerSocket.accept();
非Owner创建Socket,连接Server端。
mClientSocket = new Socket();
mClientSocket.connect((new InetSocketAddress(mHostAddress, SOCKET_PORT)), 0);
3.5 互传图片
socekt连接成功后,保留outputStream 和inputStream,并进行接收和发送的相关操作。
//获取输入输出流
mOutputStream = new DataOutputStream(mClientSocket.getOutputStream());
mInputStream = new DataInputStream(mClientSocket.getInputStream());
//不管是server还是client都接收图片。
while (!mExit) {
//循环接收图片
if(!receiveFile(mInputStream))
break;
}
发送图片
long len = file.length();
try {
//发送图片长度
mOutputStream.writeLong(len);
//获取文件输入流
FileInputStream inputStream = new FileInputStream(file);
byte buf[] = new byte[4096];
int count;
//发送图片数据
while ((count = inputStream.read(buf)) != -1) {
mOutputStream.write(buf, 0, count);
}
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
欢迎大家关注、评论、点赞。
你们的支持是我坚持的动力。
Android WiFi直连 双向通信
注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权
Android WiFi直连 双向通信的更多相关文章
- WIFI(1)WIFI直连 + socket 可以用来实现类似蓝牙传输数据的功能
WIFI 直连简介 从Android4.0(API Level=14)开始,允许通过Wi-Fi模块在两个移动设备之间建立直接连接(这种技术称为Wi-Fi Direct),这种连接不需要无线路由作为中介 ...
- Android Wi-Fi Display(Miracast)介绍
地址:http://blog.csdn.net/innost/article/details/8474683 Android Wi-Fi Display(Miracast)介绍 2012年11月中旬, ...
- (Android)Wifi-Direct直连
因项目需要Pad端和手机端交互,采用wifi直连.查阅资料,大概写下一些资料和收获吧.注:大公司的代码带不出来,我也比较懒不想再认真去写一遍了,所以大概这个意思哦. wifi直连也叫做wifi设备点对 ...
- WIFI-Direct(Wifi直连)、AirPlay、DLAN、Miracast功能介绍
不知道大家对无线同屏技术有多少了解,当这种技术普及的时候,我想我们的工作与生活又会方便很多吧!下面是目前三种主流同屏技术的介绍: 目前这种将终端信号经由WiFi传输到电视.电视盒的技术有三种:DLNA ...
- Android WIFI 分析(一)
本文基于<深入理解Android WiFi NFC和GPS 卷>和 Android N 代码结合分析 WifiService 是 Frameworks中负责wifi功能的核心服务,它主 ...
- android wifi P2P CONNECT, INVITE和JOIN流程选择
android wifi P2P CONNECT, INVITE和JOIN流程选择
- android wifi ANR问题分析总结
android wifi ANR问题分析总结 1 看看main进程阻塞在那里? 2 调用关系的函数阻塞在那里? 3 最终阻塞函数的阻塞前的log以及状态
- android wifi驱动移植详细过程
转自:http://bbs.imp3.net/thread-10558924-1-1.html 对于刚入手android没多久的人来说,android wifi 驱动的移植确实还是有难度的,不过参考了 ...
- Android WIFI 启动流程(TIP^^)
前几天因为解决一堆Bug,没时间写.我不会每天都写,就是为了存档一些资料. 内容来源:工作中接触到的+高手博客+文档(Books)=自己理解 仅限参考^^ 此博客是上一个<<Android ...
随机推荐
- [转]Android Activity和Fragment的转场动画
Android Activity和Fragment的转场动画 Activity转场动画 Activity的转场动画是通过overridePendingTransition(int enterAnim, ...
- Swify闭包
闭包:是字包含的匿名函数代码块,可以做为表达式.函数参数和函数返回值,闭包表达式的运算结果是一种函数类型.类似于 C# Lambda 表达式. 闭包表达式: {(参数列表)->返回类型 in 语 ...
- Oracle密码忘记了解决办法
Oracle密码忘记了怎么办?有时候我们可能忘记了一个用户的密码,但是又需要以这个用户做一些操作,又不能去修改掉这个用户的密码,这个时候,就可以利用一些小窍门,来完成操作.采用如下方法可以修改密码: ...
- JAVA容器-模拟ArrayList的底层实现
概述 ArrayList实质上就是可变数组的实现,着重理解:add.get.set.remove.iterator的实现,我们将关注一下问题. 1.创建ArrayList的时候,默认给数组的长度设置为 ...
- MariaDB 主从复制
MySQL Replication:NySQL复制,MySQL的复制默认为异步工作模式 mysql的复制功能是mysql内置的,装上它之后就具备了这个功能,而mysql复制是mysql实现大规模 ...
- hdu 1532 Drainage Ditches (最大流)
最大流的第一道题,刚开始学这玩意儿,感觉好难啊!哎····· 希望慢慢地能够理解一点吧! #include<stdio.h> #include<string.h> #inclu ...
- myeclipse 8.5破解方法
转自: http://blog.sina.com.cn/s/blog_70600f7201018pib.html , 记录下来存档 Step: 1.建立一个任意名称的Java Project 2.在 ...
- Unity3d 换装 之 模型动画分离
在手游中换装成了越来越不可缺的一个功能,毫无疑问各式各样的时装为游戏增添了不同的色彩. 对于2D手游,或许是更换对应的序列帧,也或许是如同3D手游一般,更换模型动画. 对于游戏中的人物,一般分为头.上 ...
- ExtJS遮罩层Ext.loadMask
一.可以直接应用在元素上,如: var loadMarsk = new Ext.LoadMask(target, { msg:'正在处理数据,请稍候......', removeMask:true / ...
- ipad2 wifi ios7.x 1.0.1还是无法越狱
原话: Warning! We have reports that the iPad 2 (wifi) is not yet compatible with the jailbreak and wil ...