TECHブログ


Wi-Fi Directを用いたソケット通信

はじめに

今回の記事ではWi-Fi Directを用いた、オフライン環境化での、相互データの送受信を行います。データの送受信を確認する手段として、ソケット通信を用いた相互に文字を送受信可能なチャットアプリで検証します。また、アプリ上からWi-Fi Directの接続を行い、データの送受信が可能な状態へ移行させます。

Wi-Fi Directとは

無線LANの規格を使用した無線通信手段であり、ルーターを使用すること無く、機器同士が直接接続し通信を行うことができる技術です。

Wi-Fi Directのデータ転送について

また、複数端末でネットワークを構築する際には、1台の端末がアクセスポイント(オーナー)となり、ネットワークのグループが作成されます。オーナー以外の端末は「クライアント」と呼ばれます。クライアント端末同士では直接の接続、通信は基本的には行われず、アクセスポイントとなっている端末を通じてデータの送受信が行われます。

クライアント端末同士での通信について

Wi-Fi Directの使用事例としては、無線通信が可能なプリンターや、ミラーリング機能が搭載されているテレビで用いられています。
同様の近距離での無線通信手段段として挙げられるBluetoothと比較します。

Bluetoothとの比較

Wi-Fi Direct Bluetooth
転送速度 800Mbps 24Mbps
距離 ~100メートル ~10メートル
バッテリー消費量 大きい 少ない
接続可能デバイス数 少ない 多い

 

搭載されているデバイス数や、消費電力といった面ではBluetoothに軍配が上がります。
しかし、タブレットやスマートフォン、PCといった限られた種類のデバイス間でのデータ通信であれば、広範囲に高速な通信をすることができる、有力な選択肢と言えるでしょう。

アプリ概要

オフライン環境下でWi-Fi Directによる接続を行い、1対1で通信を行うチャットアプリです。

※通信する両端末にアプリがインストールされ起動していることを前提としています。また、アプリへの位置情報の許可が必須となります。

開発環境

使用機材

WindowsPC

  • Windows10

Android端末

  • Huawei MediaPad M5 lite(Android9.0)

使用ソフト

  • Android Studio 2020.2.1 Patch1(Java)

アプリの実装

アプリはAndroidデベロッパー内の以下記事を参考に開発、ビルドを行いました。
Wi-Fi Direct(ピアツーピアまたは P2P)の概要

Wi-Fi Direct

実装時のセットアップ
  • Androidマニュフェストへのパーミッションの追記

AndroidのWi-Fi Direct機能を使用したアプリを開発するためには以下のパーミッションを設定する必要があります。

<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" />
  • ブロードキャストレシーバーの作成

Wi-Fi Direct使用時には特定のイベントが発生したときにアプリに通知するブロードキャストレシーバーを作成する必要があります。今回は検索プロセスへの移行時と接続状態の変更時のみ検知する必要があるため、それら2つのみを通知するものを作成しました。詳細は以下のリファレンスを確認してください
ブロードキャスト レシーバとピアツーピア マネージャーをセットアップする

 @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action))
        {
            // 検察プロセス移行時
             manager.requestConnectionInfo(channel, activity.connectionInfoListener);
        }
        else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action))
        {
           // Wifi-Direct接続状態変更時
        }
    }
接続可能デバイスの検索

チャットを行う相手端末と接続のため、
周囲にあるWi-Fi Direct対応デバイスを検索します。
Wi-Fi Directで両機器がWi-Fi Direct利用可能デバイスとして認識するためには、お互いを検索状態にする必要があります。検索を開始する際のコードは以下のようになります。
※検索時に、OSの設定上からアプリへの位置情報が許可されていない場合は結果が取得できません。

manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);

manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
    @Override
    public void onSuccess() {
        ...
    }

    @Override
    public void onFailure(int reasonCode) {
        ...

    }
});

上記コード上の「onSuccess()」「onFailure(int reasonCode)」はWi-Fi Directが検索プロセスが成功したことを通知するのみで、実際にどのようなデバイスが検出できたのかは通知しません。
成功した場合は、ブロードキャストレシーバー内の「WIFI_P2P_PEERS_CHANGED_ACTION」から「manager.requestPeers」が呼び出され検索プロセスに移行しています。

検索結果の取得

検索プロセスに移行後、以下の処理で検索結果を取得しています。
コード内の「peers」リスト内に、検出できた全デバイス情報を「WifiP2pDevice」の形式で格納しています。

private List<WifiP2pDevice> peers = new ArrayList<WifiP2pDevice>();
    ...

    WifiP2pManager.PeerListListener peerListListener = new WifiP2pManager.PeerListListener() {
        //Wifi-Directが検索状態になった際に呼び出し
        @Override
        public void onPeersAvailable(WifiP2pDeviceList wifiP2pDeviceList) {
            if (!wifiP2pDeviceList.equals(peers)) {
                peers.clear();
                peers.addAll(wifiP2pDeviceList.getDeviceList());
                ...

                for (WifiP2pDevice device : peers) {

                    // タブレットのみを判別
                    if (device.primaryDeviceType.startsWith("10"))
                    {
                        // リストへの追加処理
                        ...
                    }
                }
            }
            if (peers.size() == 0) {
                // デバイスが発見できなかった場合
                ...
                return;
            }
        }
    };
}

検索時に他のWi-Fi Direct対応機器から取得できる「WifiP2pDevice」内の情報は以下の5つです。

  1. deviceAddress(デバイスのMACアドレス)
  2. deviceName(デバイス名)
  3. primaryDeviceType(デバイスの種類)
  4. secondaryDeviceType(デバイスの種類のオプション)
  5. status(デバイスの接続状態)

検索時に今回の接続対象であるAndroidタブレット以外を除外する方法として、「primaryDeviceType」による判定を行いました。
「primaryDeviceType」を用いることで、検出できたデバイスがどのような種類の機器なのかを判断することが出来ます。
(例: プリンター→[7-0050F204-1],PC→[1-0050F204-1])

今回はAndroidタブレットのみをリストに追加したいため、「primaryDeviceType」が”10″から始まる「WifiP2pDevice」をプルダウンのリストに追加します。

選択端末への接続

接続可能なデバイスの検索結果から、接続したいWi-Fi Direct利用可能端末に、接続処理を行います。
以下のコードで接続したい端末へ接続要求を送ることができます。

WifiP2pDevice device;
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
manager.connect(channel, config, new ActionListener() {

    @Override
    public void onSuccess() {
       ...
    }

    @Override
    public void onFailure(int reason) {
        ...
    }
});

検索時と同様に、上記コード上の「onSuccess()」「onFailure(int reasonCode)」はWi-Fi Direct接続要求の送信プロセスが成功したことを通知するのみとなり、接続要求を許可したかどうかについては通知しません。

接続要求を受信した端末には、以下のようなダイアログが表示されます。
「許可する」を選択することで、2デバイス間にWi-Fi Directの接続が確立されます。

接続確認ダイアログスクリーンショット

Wi-Fi Directの接続が確立することで相互にデータの送受信が行うことができるようになります。

Wi-Fi Directのオーナー

今回の接続方法では自動的にオーナーデバイスが割り当てられ、Wi-Fi Directネットワークのグループが作成されます。そのため、グループの他デバイスとの接続状況により以下の5種類のいずれかの接続が行われます。

  1. グループが作成されていない場合
    →自動的にネットワークのグループが作成され、接続要求の送信側、受信側のいずれか一方がオーナーとなる。
  2. 既にグループが作成されており、クライアント端末①から未接続端末に接続要求を送信した場合
    →オーナー端末がアクセスポイントとなるため、オーナー端末から未接続端末へ接続要求が送られる。
    ※接続を許可した際にはクライアント端末②になる。
  3. 既にグループが作成されており、オーナー端末から未接続端末へ接続要求を送信した場合
    →未接続端末がクライアント端末②となる。
  4. 既にグループが作成されており、未接続端末からクライアント端末①に接続要求を送信した場合
    →接続要求の送信に失敗する
  5. 既にグループが作成されており、未接続端末からオーナー端末へ接続要求を送信した場合
    →未接続端末がクライアント端末②となる。

ソケット通信

今回のアプリではソケット通信を用いるため、IPアドレスを取得する必要がありました。
Wi-Fi Direct使用時はオーナー(アクセスポイント端末)へは固定の値(192.168.49.1)が与えられます。
同様に、クライアント(オーナー以外の端末)には(192.168.49.*)のアドレスがDHCPによって自動的に割り当てられます。
今回のアプリではWi-Fi Directによる接続後、以下の流れでチャット可能端末のIPアドレスを取得し、クライアント端末同士での通信を可能にしています。

  1. クライアント自身のIPアドレスとデバイス名をオーナーへ送信
  2. オーナー端末で接続済みのデバイス情報リストの更新
  3. ネットワークに接続済みの他クライアント名とIPアドレスをオーナーから取得

デモ動画

動画補足

プルダウン表示内容

アプリ内のプルダウンにはそれぞれ以下のデバイスのリストが表示されています。

  • Wifi-Direct利用可 → 検索したのWifi-Directが接続可能な端末
  • Wifi-Direct接続済み → Wifi-Directが接続されており、データの送受信が可能な端末
  • チャット可能端末 → 同じアプリケーションが起動されているチャット可能端末
クライアントデバイス間での通信

DT0C0006(クライアントデバイス①)からDTC00002(クライアントデバイス②)へWi-Fi Directs接続要求を送る際に、画面上にはDTC0007(オーナーデバイス)から招待を受けた表示になっています。これは、Wi-Fi Directの接続はクライアント端末同士では接続されず、クライアント①が接続されているオーナーデバイスに自動的に接続されるためです。

まとめ

Wi-Fi Directを用いることでオフライン環境化でもソケット通信を行い、相互にデータの送受信が行えられることを確認できました。また、割り当てられたIPアドレスを用いることで、同じネットワークのグループ内であれば、相互にデータの送受信が可能であることを確認できました。
Wi-Fiの通信規格を使用していることから、Wi-Fi通信の性能向上によって、より広範囲かつ高速な通信が可能になるでしょう。ルーターを設置できない場所での通信手段として、また、オフィス内でのデータのやり取りとしてなど、そのような限られた環境下では高い能力を発揮することができそうです。