zoukankan      html  css  js  c++  java
  • Android WiFi直连 双向通信

    代码地址如下:
    http://www.demodashi.com/demo/13965.html

    原文地址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 搜索不到可用设备

    1. 确保对端设备处于搜索状态;
    2. 对端设备异常,可尝试重启WLAN开关,重新搜索。
    3. 自身设备异常,可尝试重启WLAN开关,重新搜索。

    2.2 连接失败

    1. 确保对端设备没有与其他设备建立WLAN直连连接。
    2. 确保对端设备接收连接请求。
    3. 对端设备异常,请尝试重新连接。

    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直连 双向通信

    代码地址如下:
    http://www.demodashi.com/demo/13965.html

    注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权

  • 相关阅读:
    CODING x 百果园 _ 水果零售龙头迈出 DevOps 体系建设第一步
    Nocalhost 亮相 CD Foundation 国内首届 Meetup,Keith Chan 将出席致辞
    做云原生时代标准化工具,实现高效云上研发工作流
    打造数字化软件工厂 —— 一站式 DevOps 平台全景解读
    WePack —— 助力企业渐进式 DevOps 转型
    CODING Compass —— 打造行云流水般的软件工厂
    Nocalhost —— 让云原生开发回归原始而又简单
    CODING 代码资产安全系列之 —— 构建全链路安全能力,守护代码资产安全
    Nocalhost:云原生开发新体验
    使用 Nocalhost 开发 Kubernetes 中的 APISIX Ingress Controller
  • 原文地址:https://www.cnblogs.com/demodashi/p/9582568.html
Copyright © 2011-2022 走看看