日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

WIFI P2P原理深入解析

發布時間:2024/3/12 编程问答 59 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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 的代碼如下:

public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {private WifiP2pManager manager; private Channel channel; private MyWiFiActivity activity;public WiFiDirectBroadcastReceiver (WifiP2pManager manager, Channel channel,MyWifiActivity activity) { super(); this.manager=manager; this.channel=channel; this.activity=activity; } @Override public void onReceive(Context context, Intent intent) { String action=intent.getAction();if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTI0N.equals (action)) { //檢測 WIFI 功能是否被打開 } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals (action)) { //獲取當前可用連接點的列表 } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals (action)) { //建立或者斷開連接 } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals (action)) { //當前設備的 WIFI 狀態發生變化 } } }

2. 初始化操作

1)修改?AndroidManifest.xml 文件

指定支持 WIFI Direct 的 Android SDK 的最小版本并增加使用 WIFI Direct 的相應權限,代碼如下:

<uses-sdk android:minSdkVersion="14" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <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" />

2)確認當前設備是否支持并且打開了 WIFI Direct 功能

相關代碼應該被放在 BroadcastReceiver 的 onReceive() 方法中。實例代碼如下:

public void onReceive (Context context, Intent intent) { ... String action=intent.getAction();if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTI0N.equals (action)) { int state=intent.getIntExtra (WifiP2pManager.EXTRA_WIFI_STATE, -1); if (state==WifiP2pManager.WIFI_P2P_STATE_ENABLED) { // Wifi Direct is enabled } else { // Wi-Fi Direct is not enabled } } ... }

3)在 Activity 的 onCreate() 方法中創建對象

創建 WifiP2pManager 和 Channel 對象,并創建 BroadcastReceiver 對象,代碼如下:

WifiP2pManager mManager; Channel mChannel; BroadcastReceiver mReceiver; ...@Override protected void onCreate (Bundle savedInstanceState) { ... mManager= (WifiP2pManager) getSystemService (Context.WIFI_P2P_SERVICE); mChannel=mManager.initialize (this, getMainLooper(), null); mReceiver=new WiFiDirectBroadcastReceiver (manager, channel, this); ... }

4)創建 BroadcastReceiver 要使用的 IntentFilter 對象

代碼如下:

IntentFilter mIntentFilter; ... @Override protected void onCreate (Bundle savedInstanceState) { ... mIntentFilter=new IntentFilter(); mIntentFilter.addAction (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTI0N); mIntentFilter.addAction (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTI0N); mIntentFilter.addAction (WifiP2pManager.WIFI_P2P_C0NNECTI0N_CHANGED_ACTI0N); mIntentFilter.addAction (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTI0N); ... }

5)在 Activity 的 onResume() 方法中注冊 BroadcastReceiver 對象,在 onPause() 方法中注銷對象

代碼如下:

@Override protected void onResume(){ super.onResume(); registerReceiver(mReceiver, mIntentFilter); }/*unregister the broadcast receiver */ @Override protected void onPause(){ super.onPause(); unregisterReceiver(mReceiver); }

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 圖像的過程。

服務器代碼如下:

public static class FileServerAsyncTask extends AsyncTask { private Context context; private TextView statusText;public FileServerAsyncTask(Context context, View statusText) { this.context = context; this.statusText = (TextView) statusText; }@Override protected String doInBackground(Void... params) { try { //創建 ServerSocket 對象,監聽 8888 端口,等待客戶連接 ServerSocket serverSocket = new ServerSocket(8888); Socket client = serverSocket.accept(); //建立連接成功,開始傳送數據 final File f = new File(Environment.getExternalStorageDirectory() + "/" + context.getPackageName() + "/wifip2pshared-" + System.currentTimeMillis() + ".jpg"); File dirs = new File(f.getParent()); if (!dirs.exists()) dirs.mkdirs(); f.createNewFile(); InputStream inputstream = client.getlnputStream(); copyFile(inputstream, new FileOutputStream(f)); ServerSocket.close(); return f.getAbsolutePath(); } catch (IOException e) { Log.e(WiFiDirectActivity.TAG, e.getMessage()); return null; } }//啟動用于顯示圖像的Activity @Override protected void onPostExecute(String result) { if (result != null) { statusText.setText("File copied - " + result); Intent intent = new Intent(); intent.setAction(android.content.Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse("file://" + result),"image/*"); context.startActivity(intent); } } }

客戶端的相關代碼如下:

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原理深入解析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。