WIFI P2P原理深入解析
目錄
前言
1.原理及架構
2.實例及應用
3.常見的問題
前言
? ? ? ? 對Wi-Fi Direct即wifi直連,在物聯,中短距離的傳輸穩定性明顯比藍牙具有優勢,本文主要介紹兩個方面:一是原理及架構,二是實例及應用;
1.原理及架構
P2P架構中定義了三個組件,一個設備,兩種角色。這三個組件分別是:
- P2P Device:它是P2P架構中角色的實體,讀者可把它當做一個Wi-Fi設備。
- P2P Group Owner(GO):P2P網絡建立時會產生一個Group。
- P2P Group Client(GC):
- 在組建P2P Group(即P2P Network)之前,智能終端都是一個一個的P2P Device。
- 當這些P2P Device設備之間完成P2P協商后,那么其中將有一個并且只能有一個Device來扮演GO的角色,而其他Device來扮演GC的角色。
最終構成的這個P2P Group組織結構如圖所示:
?P2P Group示意圖
如圖展示了一個典型P2P Group的構成,其中:
一個P2P Group中只能有一個GO。一個GO可以支持1個或多個(即圖中的1:n)GC連接。
- 由于GO的功能類似于AP,所以周圍那些不支持P2P功能的WIFI STA也能發現并關聯到GO。這些WIFI STA被稱之為Legacy Clients。
注意:“不支持P2P功能”更準確的定義是指不能處理P2P協議。在P2P網絡中,GO等同于AP,所以Legacy Clients也能搜索到GO并關聯上它。不過,由于Legacy Clients不能處理P2P協議,所以P2P一些特有功能在這些Legacy Clients中無法實現。
Wifi_Direct的大致配對流程如下:
? ? ? ? a. WifiP2pManager.discoverPeers()開始掃描設備
? ? ? ? b. 獲取掃描到的設備,選擇其中一個設備進行連接配對WifiP2pManager.connect
? ? ? ? c. 配對成功后,根據WifiP2pInfo.isGroupOwner和WifiP2pInfo.groupOwnerAddress進行連接。
? ? ? ? 雙方時序圖如下:
2.實例及應用
創建一個 WIFI Direct 應用程序,包括發現連接點、請求連接、建立連接、發送數據,以及建立對該應用程序廣播的 Intent 進行接收的 BroadcastReceiver,需要經過以下步驟。
1. 創建 BroadcastReceiver
需要注意的是,要在 BroadcastReceiver 的構造方法中傳入 WifiP2pManager、WifiP2pManager.Channel 以及注冊該 BroadcastReceiver 的 Activity 的對象,以便在 BroadcastReceiver 中訪問 WIFI 硬件設備并對 Activity 進行更新。
創建 BroadcastReceiver 的代碼如下:
2. 初始化操作
1)修改?AndroidManifest.xml 文件
指定支持 WIFI Direct 的 Android SDK 的最小版本并增加使用 WIFI Direct 的相應權限,代碼如下:
2)確認當前設備是否支持并且打開了 WIFI Direct 功能
相關代碼應該被放在 BroadcastReceiver 的 onReceive() 方法中。實例代碼如下:
3)在 Activity 的 onCreate() 方法中創建對象
創建 WifiP2pManager 和 Channel 對象,并創建 BroadcastReceiver 對象,代碼如下:
4)創建 BroadcastReceiver 要使用的 IntentFilter 對象
代碼如下:
5)在 Activity 的 onResume() 方法中注冊 BroadcastReceiver 對象,在 onPause() 方法中注銷對象
代碼如下:
3. 使用 WifiP2pManager.discoverPeers() 方法獲取可以連接點的列表
示例代碼如下:
manager.discoverPeers (channel, new WifiP2pManager.ActionListener() { @Override public void onSuccess(){ ... }@Override public void onFailure (int reasonCode) { ... } });若成功搜尋到可以連接的點,則 WIFI Direct 系統框架會廣播一個帶有 WIFI_P2P_ PEERS_CHANGED_ACTION 信息的 Intent,該 Intent 會被之前定義的 BoradcastReceiver 接收,并獲得可以連接點的列表。示例代碼如下:
PeerListListener myPeerListListener; ... if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals (action)) { if (manager !=null) { manager.requestPeers (channel, myPeerListListener); } }4. WifiP2pManager.connect() 方法可以與列表中的某個連接點設備建立連接,該方法通過 WifiP2pConfig 對象獲得連接設備的相關信息
示例代碼如下:
WifiP2pDevice device; WifiP2pConfig config=new WifiP2pConfig(); config.deviceAddress=device.deviceAddress; manager.connect (channel, config, new ActionListener () {@Override public void onSuccess(){ //success logic }@Override public void onFailure (int reason) { //failure logic } });5. 連接建立后,就可以用兩個設備直接通過 Socket 進行數據傳輸
其傳輸過程與之前講解的 Socket 通信完全相同,基本步驟如下:
1)在其中一個設備上建立 ServerSocket 對象,監聽特定端口,并堵塞應用程序,直到有連接請求。
2)在另一個設備上建立 Socket 對象,通過 IP 地址和端口向 ServerSocket 發出連接請求。
3)ServerSocket 監聽到連接請求后,調用 accept() 方法建立連接。
4)連接建立后,Socket 對象可以通過字節流在兩個設備間直接進行數據傳遞。
下面的示例代碼演示了通過 ServerSocket 和 Socket 在客戶端和服務器間直接傳遞 JPG 圖像的過程。
服務器代碼如下:
客戶端的相關代碼如下:
Context context=this.getApplicationContext(); String host; int port; int len; Socket socket=new Socket(); byte buf[]=new byte[1024]; ... try{ //創建Socket對象,并請求連接 socket.bind (null); socket.connect((new InetSocketAddress(host,port)),500);//連接建立成功,開始傳輸數據 OutputStream outputStream=socket.getOutputStream(); ContentResolver cr=context.getContentResolver(); Inputstream inputStream=null; inputstream=cr.openlnputStream(Uri.parse("path/to/picture.jpg"))while((len=inputStream.read(buf))!=-l){outputStream.write(buf,0,len); outputStream.close(); inputstream.close(); }catch(FileNotFoundException e){ //catch logic } catch (IOException e) { //catch logic } //關閉連接 finally{ if(socket!=null){ if(socket.isConnected()){ try{ socket.close(); }catch(IOException e){ //catch logic } } } }3.常見的問題
問題1:WifiP2pManger.connect()時,如何確定誰是GO,誰是GC
答:調用WifiP2pManger.connect()進行連接時,GO還算GC的身份是隨機的。開發者無法決定GroupOwner是哪臺設備,但是可以通過WifiP2pConfig.groupOwnerIntent參數進行建議。
問題2:如果一定要確定誰是GO,誰是GC,怎么辦
答:第一步:GO端先調用WifiP2pManger.createGroup
第二步:GO端或者GC端調用WifiP2pManger.connect
即:先建立Group,再連接
問題3:如何斷開連接
答:WifiP2pManger.removeGroup
注意:WifiP2pManger.removeGroup是移除Group,斷開連接。WifiP2pManger.cancelConnect()斷開一個connecting的連接,即斷開當前狀態是Invited的連接。
問題4:?我們已知配對成功的前提條件是:進行配對的兩臺設備都必須能夠掃描到對方。那么如何保證本機一直處于搜索狀態呢?
答:經過測試得知,一般情況下,本機Scan一次,能夠保持在線狀態3分鐘,即能夠搜索到其他設備/被其他設備搜索到的時間一般是3分鐘。但是這個3分鐘不是非常準確的,這跟手機性能或者WIFI芯片都有很大關系。因此我們能做的方案就是如果搜索結束,就重啟一次搜索。
對于一般的Peer Discovery而言,如果搜索結束,會收到廣播WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION,這樣再收到廣播后重新搜索就可以。
對于Service Discovery而言(這其實是使用最廣泛的),搜索結束后,系統不會發出廣播通知,這樣就給開發者帶來一個難題:你無法知曉當前是否處于搜索(可見)狀態。
目前比較可行的做法是:每隔3分鐘(或者更短)重啟一次搜索,這樣基本保證本機一直處于搜索狀態。但是這僅能覆蓋大多數的情況,建議再此基礎上再加入手動搜索(搜不到可以讓用戶手動搜索)保證當前的可見狀態。
目前wifip2p依然不是很穩定,從測試的結果來說,Wifi_Direct的表現受具體設備的影響很大,配對的速度也有較大差異,從10秒到2分鐘甚至更久。有可能出現
a.A機器處于搜索(可見)狀態,但是B機器依然搜索不到;
b.還有可能出現A機器處于搜索(可見)狀態,B機器也搜索到了,但是連接失敗(此情況的主要原因還是因為A機器搜索結束后系統不發通知,而B機器當前搜索到的A機器是之前A機器的狀態)
問題5:如何把一個文件非常方便的發送給多個設備
答:
方法1:在一次一對一文件傳輸完畢后,直接斷開連接進行搜索/連接/傳輸,這樣就可以實現相同文件(夾)的多目標設備的發送。
方法2:使用問題2的答案,發送方做GO,接收方全部做GC,即可。
問題6:
我們知道
1.在進行connect的時候,連接兩端是GO還是GC是隨機的。
2.GC可以知道GO的地址,而GO是不知道GC的地址的.
3.一般的Socket編程思路是,GO做Server端,GC做Client端。
那么問題來了,如何能夠實現PeerA連接PeerB后,PeerA直接發送數據給PeerB呢?
答:方法一:使用問題2中的答案,先確定身份(誰是GO,誰是GC),再發送數據
方法二:步驟(假設PeerA是數據發送端,PeerB是數據接收端)
1.connect成功后,GO做server,GC做client
2.socket連接成功后,PeerA執行發送線程,PeerB執行接收線程
總結
以上是生活随笔為你收集整理的WIFI P2P原理深入解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2022年必读的10本好书
- 下一篇: buck dcm占空比计算_如何计算BO