自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

走進Android WiFi P2P技術(shù),一探設(shè)備間點對點通信實現(xiàn)細(xì)節(jié)

移動開發(fā) Android
WiFi P2P被廣泛應(yīng)用于移動設(shè)備之間的文件共享、游戲聯(lián)機、音樂播放等應(yīng)用場景中。相較于藍(lán)牙,WiFi P2P具有更快的搜索速度和傳輸速度,以及更遠(yuǎn)的傳輸距離。而且只需要打開WiFi即可,不需要加入任何網(wǎng)絡(luò)或AP,即可實現(xiàn)對等點連接通訊。對于需要在用戶之間共享數(shù)據(jù)的應(yīng)用,如多人游戲或照片共享非常有用。

WiFi P2P技術(shù)

WiFi P2P(Peer-to-Peer),也被稱為WiFi Direct,是WiFi聯(lián)盟發(fā)布的一個協(xié)議。允許無線網(wǎng)絡(luò)中的設(shè)備在無需無線路由器的情況下相互連接,通過WiFi直接實現(xiàn)兩臺設(shè)備之間的無線點對點通信。原理與基于AP(接入點)的通信方式類似,支持P2P的設(shè)備可以在同一個小組內(nèi)互傳數(shù)據(jù),實現(xiàn)同屏功能。

WiFi P2P被廣泛應(yīng)用于移動設(shè)備之間的文件共享、游戲聯(lián)機、音樂播放等應(yīng)用場景中。相較于藍(lán)牙,WiFi P2P具有更快的搜索速度和傳輸速度,以及更遠(yuǎn)的傳輸距離。而且只需要打開WiFi即可,不需要加入任何網(wǎng)絡(luò)或AP,即可實現(xiàn)對等點連接通訊。對于需要在用戶之間共享數(shù)據(jù)的應(yīng)用,如多人游戲或照片共享非常有用。

WiFi P2P也存在一些安全性問題,如用戶隱私泄露、惡意軟件和病毒傳播,以及侵權(quán)和違法內(nèi)容的傳播。為了保護用戶的安全和隱私,一些P2P網(wǎng)絡(luò)提供了匿名化處理功能,使用安全搜索引擎,以及設(shè)置過濾器來阻止違法和侵權(quán)內(nèi)容的共享。

Android WiFi P2P架構(gòu)

在P2P架構(gòu)中,定義了兩種主要角色:P2P Group Owner(簡稱GO)和P2P Client(簡稱GC)。GO的作用類似于Infrastructure BSS中的AP(接入點),而GC的作用類似于Infrastructure BSS中的STA(站點)。當(dāng)兩臺設(shè)備通過P2P連接后,會隨機(也可以手動指定)指派其中一臺設(shè)備為組擁有者(GO),相當(dāng)于一臺服務(wù)器,另一臺設(shè)備為組成員(GC)。其他設(shè)備可以通過與GO設(shè)備連接加入組,但不能直接和GC設(shè)備連接。

圖片圖片

在Android系統(tǒng)中,WiFi P2P功能是在Android 4.0及更高版本系統(tǒng)中加入的。它可以通過WifiP2pManager類進行實現(xiàn),這個類提供了許多方法來掃描可用設(shè)備、建立P2P連接并傳輸數(shù)據(jù)等功能。開發(fā)者可以通過這些方法來實現(xiàn)設(shè)備之間的文件傳輸?shù)炔僮鳌?/p>

在設(shè)備發(fā)現(xiàn)階段,Android WiFi P2P使用Probe Request和Probe Response幀來交換設(shè)備信息。在2.4GHz的1、6、11頻段上發(fā)送Probe Request幀,這幾個頻段被稱為Social Channels。一旦Listen Channel選擇好后,在整個P2P Discovery階段就不能更改,用于快速發(fā)現(xiàn)周圍的Group。

盡管Android WiFi P2P功能強大,目前在Android系統(tǒng)中只是內(nèi)置了設(shè)備的搜索和鏈接功能,并沒有像藍(lán)牙那樣有許多應(yīng)用。在實際開發(fā)中,可能需要通過軟件手段解決一些邏輯和權(quán)限問題。

Android應(yīng)用WiFi P2P實現(xiàn)數(shù)據(jù)傳輸

在Android中,WiFi P2P可以通過WifiP2pManager類進行實現(xiàn)。開發(fā)者可以通過獲取WifiP2pManager實例,并進行廣播接受者的創(chuàng)建和注冊,調(diào)用其他WiFi P2P的API,實現(xiàn)設(shè)備間的搜索、連接和數(shù)據(jù)傳輸?shù)裙δ?。例如,指定某一臺設(shè)備為服務(wù)器,創(chuàng)建群組并等待客戶端的連接請求,而客戶端則可以主動搜索附近的設(shè)備并加入群組,向服務(wù)器發(fā)起文件傳輸請求。

圖片圖片

添加權(quán)限
<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.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
獲取WifiP2pManager和WifiP2pManager.Channel對象
mWifiP2pManager = getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager
mWifiP2pManager?.initialize(this, Looper.getMainLooper()) {
    Log.d(TAG, "Channel斷開連接")
}
服務(wù)端創(chuàng)建群組
//服務(wù)端創(chuàng)建群組
mWifiP2pManager?.createGroup(mChannel, object : WifiP2pManager.ActionListener {
    override fun onSuccess() {
        Log.d(TAG, "創(chuàng)建群組成功")
    }

    override fun onFailure(reason: Int) {
        Log.w(TAG, "創(chuàng)建群組失敗$reason")
    }
})
客戶端搜索對等設(shè)備
//客戶端搜索對等設(shè)備
mWifiP2pManager?.discoverPeers(mChannel, object : WifiP2pManager.ActionListener {
    override fun onSuccess() {
        Log.d(TAG, "搜索成功")
    }

    override fun onFailure(reason: Int) {
        Log.d(TAG, "搜索失敗:$reason")
    }

})
//使用異步方法(推薦通過廣播監(jiān)聽) 獲取設(shè)備列表
mWifiP2pManager?.requestPeers(mChannel) {
    mDeviceList.addAll(it.deviceList)
    if (mDeviceList.isEmpty()) {
        //沒有設(shè)備
        runOnUiThread { Toast.makeText(this, "沒有發(fā)現(xiàn)設(shè)備", Toast.LENGTH_SHORT).show() }
    } else {
        //刷新列表
        runOnUiThread { mDeviceAdapter.notifyDataSetChanged() }
    }
}
連接設(shè)備
val config = WifiP2pConfig().apply {
    this.deviceAddress = wifiP2pDevice.deviceAddress
    this.wps.setup = WpsInfo.PBC
}
mWifiP2pManager?.connect(mChannel, config, object : WifiP2pManager.ActionListener {
    override fun onSuccess() {
        Log.d(TAG, "連接成功")
    }

    override fun onFailure(reason: Int) {
        Log.w(TAG, "連接失敗$reason")
    }

})
服務(wù)端創(chuàng)建Socket進行數(shù)據(jù)讀寫
// 將數(shù)據(jù)發(fā)送給客戶端
//需要創(chuàng)建子線程 否則在主線程網(wǎng)絡(luò)操作直接閃退
val serverSocket = ServerSocket(8888)
val socket = serverSocket.accept()
val inputStream = socket.getInputStream()
val outputStream = socket.getOutputStream()
//發(fā)送數(shù)據(jù)
outputStream?.write(data)
//此處為了方便 實際需要開啟線程讀取 并且要有合適的延遲
while (!mQuitReadData) {
    val reader = inputStream.bufferedReader(StandardCharsets.UTF_8)
    val text = reader.readLine()
    Log.d(TAG, "讀取到的數(shù)據(jù)$text")
}
客戶端創(chuàng)建Socket進行數(shù)據(jù)讀寫
//需要創(chuàng)建子線程 否則在主線程網(wǎng)絡(luò)操作直接閃退
val address: InetAddress = info.groupOwnerAddress
val socket = Socket(address, 8888)
val inputStream = socket.getInputStream()
val outputStream = socket.getOutputStream()
//發(fā)送數(shù)據(jù)
outputStream?.write(data)
//此處為了方便 實際需要開啟線程讀取 并且要有合適的延遲
while (!mQuitReadData) {
    val reader = inputStream.bufferedReader(StandardCharsets.UTF_8)
    val text = reader.readLine()
    Log.d(TAG, "讀取到的數(shù)據(jù)$text")
}
class MainActivity : AppCompatActivity() {

    private val TAG = MainActivity::class.java.simpleName

    private lateinit var mBinding: ActivityMainBinding

    private var mWifiP2pManager: WifiP2pManager? = null
    private var mChannel: WifiP2pManager.Channel? = null

    private var mDeviceList = arrayListOf<WifiP2pDevice>()
    private lateinit var mDeviceAdapter: DeviceAdapter

    private var mQuitReadData = true

    @SuppressLint("NotifyDataSetChanged")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        mBinding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(mBinding.root)
        ViewCompat.setOnApplyWindowInsetsListener(mBinding.main) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }

        val intentFilter = IntentFilter()
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION)
        registerReceiver(mReceiver, intentFilter)

        mDeviceAdapter = DeviceAdapter(mDeviceList)
        mBinding.rvDeviceList.adapter = mDeviceAdapter
        mDeviceAdapter.mOnItemSelectedListener = object : OnItemSelectedListener {
            override fun onItemSelected(
                parent: AdapterView<*>?,
                view: View?,
                position: Int,
                id: Long
            ) {
                val wifiP2pDevice = mDeviceList[position]
                connect(wifiP2pDevice)
            }

            override fun onNothingSelected(parent: AdapterView<*>?) {
            }
        }

        //通用步驟
        mWifiP2pManager = getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager

        mChannel = mWifiP2pManager?.initialize(this, Looper.getMainLooper()) {
            Log.d(TAG, "Channel斷開連接")
        }

        //服務(wù)端部分
        //服務(wù)端創(chuàng)建群組
        mWifiP2pManager?.createGroup(mChannel, object : WifiP2pManager.ActionListener {
            override fun onSuccess() {
                Log.d(TAG, "創(chuàng)建群組成功")
            }

            override fun onFailure(reason: Int) {
                Log.w(TAG, "創(chuàng)建群組失敗$reason")
            }
        })

        //客戶端部分
        //客戶端搜索對等設(shè)備
        mWifiP2pManager?.discoverPeers(mChannel, object : WifiP2pManager.ActionListener {
            override fun onSuccess() {
                Log.d(TAG, "搜索成功")
            }

            override fun onFailure(reason: Int) {
                Log.d(TAG, "搜索失敗:$reason")
            }

        })

        //使用異步方法(推薦通過廣播監(jiān)聽) 獲取設(shè)備列表
        mWifiP2pManager?.requestPeers(mChannel) {
            mDeviceList.addAll(it.deviceList)
            if (mDeviceList.isEmpty()) {
                //沒有設(shè)備
                runOnUiThread { Toast.makeText(this, "沒有發(fā)現(xiàn)設(shè)備", Toast.LENGTH_SHORT).show() }
            } else {
                //刷新列表
                runOnUiThread { mDeviceAdapter.notifyDataSetChanged() }
            }
        }
    }

    /**
     * 連接設(shè)備
     */
    private fun connect(wifiP2pDevice: WifiP2pDevice) {
        val config = WifiP2pConfig().apply {
            this.deviceAddress = wifiP2pDevice.deviceAddress
            this.wps.setup = WpsInfo.PBC
        }
        mWifiP2pManager?.connect(mChannel, config, object : WifiP2pManager.ActionListener {
            override fun onSuccess() {
                Log.d(TAG, "連接成功")
                mQuitReadData = false
                transferData("Hello".toByteArray())
            }

            override fun onFailure(reason: Int) {
                Log.w(TAG, "連接失敗$reason")
                mQuitReadData = true
            }

        })
    }

    private fun transferData(data: ByteArray) {
        //請求設(shè)備連接信息
        mWifiP2pManager?.requestConnectionInfo(mChannel) { info ->
            if (info.groupFormed && info.isGroupOwner) {
                // 將數(shù)據(jù)發(fā)送給客戶端
                val serverSocket = ServerSocket(8888)
                val socket = serverSocket.accept()
                val inputStream = socket.getInputStream()
                val outputStream = socket.getOutputStream()
                //發(fā)送數(shù)據(jù)
                outputStream?.write(data)
                //此處為了方便 實際需要開啟線程讀取 并且要有合適的延遲
                while (!mQuitReadData) {
                    val reader = inputStream.bufferedReader(StandardCharsets.UTF_8)
                    val text = reader.readLine()
                    Log.d(TAG, "讀取到的數(shù)據(jù)$text")
                }
            } else {
                //設(shè)備是客戶端
                val address: InetAddress = info.groupOwnerAddress
                val socket = Socket(address, 8888)
                val inputStream = socket.getInputStream()
                val outputStream = socket.getOutputStream()
                //發(fā)送數(shù)據(jù)
                outputStream?.write(data)
                //此處為了方便 實際需要開啟線程讀取 并且要有合適的延遲
                while (!mQuitReadData) {
                    val reader = inputStream.bufferedReader(StandardCharsets.UTF_8)
                    val text = reader.readLine()
                    Log.d(TAG, "讀取到的數(shù)據(jù)$text")
                }
            }
        }
    }

    private val mReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            val action = intent?.action;
            if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
                // Check to see if Wi-Fi is enabled and notify appropriate activity
                // 檢查 Wi-Fi P2P 是否已啟用
                val state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1)
                val isEnabled = (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED)
            } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
                // Call WifiP2pManager.requestPeers() to get a list of current peers
                //異步方法
                // mWifiP2pManager?.requestPeers();
            } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
                // Respond to new connection or disconnections
                // 鏈接狀態(tài)變化回調(diào)
                // 此廣播 會和 WIFI_P2P_THIS_DEVICE_CHANGED_ACTION 同時回調(diào)
                // 注冊廣播、連接成功、連接失敗 三種時機都會調(diào)用
                // 應(yīng)用可使用 requestConnectionInfo()、requestNetworkInfo() 或 requestGroupInfo() 來檢索當(dāng)前連接信息。
            } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
                // Respond to this device's wifi state changing
                // 此設(shè)備的WiFi狀態(tài)更改回調(diào)
                // 此廣播 會和 WIFI_P2P_CONNECTION_CHANGED_ACTION 同時回調(diào)
                // 注冊廣播、連接成功、連接失敗 三種時機都會調(diào)用
                // 應(yīng)用可使用 requestDeviceInfo() 來檢索當(dāng)前連接信息。
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        //移除群組
        mWifiP2pManager?.removeGroup(mChannel, null)
        //取消鏈接
        mWifiP2pManager?.cancelConnect(mChannel, null)
    }
}

Android WiFi P2P使用流程總結(jié):

  1. 「權(quán)限聲明」:

在AndroidManifest.xml中聲明必要的權(quán)限,包括網(wǎng)絡(luò)訪問權(quán)限和文件讀寫權(quán)限。

  1. 「初始化」:

在Android應(yīng)用中,首先需要獲取WifiP2pManager實例,并通過調(diào)用其initialize方法進行初始化。這將注冊應(yīng)用并準(zhǔn)備使用Wi-Fi P2P功能。

初始化完成后,會獲得一個Channel對象,它是后續(xù)操作的關(guān)鍵。

3.「廣播接收與處理」:

在整個過程中,應(yīng)用需要注冊并監(jiān)聽特定的廣播,以處理Wi-Fi P2P狀態(tài)變化、設(shè)備發(fā)現(xiàn)、連接變化等事件。

這些廣播會通知應(yīng)用有關(guān)Wi-Fi P2P操作的狀態(tài)和結(jié)果,以便應(yīng)用可以做出相應(yīng)的響應(yīng)。

4.「設(shè)備發(fā)現(xiàn)」:

使用WifiP2pManager的discoverPeers方法開始搜索附近的Wi-Fi P2P設(shè)備。

設(shè)備會在特定的頻段(如2.4GHz的1、6、11頻段)上發(fā)送Probe Request幀來尋找其他設(shè)備。

搜索到的設(shè)備會作為列表展示在應(yīng)用界面上,用戶可以從中選擇想要連接的設(shè)備。

5.「建立連接」:

選定一個設(shè)備后,作為客戶端或服務(wù)端(Group Owner,GO)發(fā)起連接請求。

通過WifiP2pConfig對象配置連接參數(shù),如目標(biāo)設(shè)備的地址和WPS(Wi-Fi Protected Setup)設(shè)置。

使用WifiP2pManager的connect方法嘗試建立連接。

6.「連接確認(rèn)與數(shù)據(jù)傳輸」:

一旦連接建立成功,設(shè)備之間就可以開始數(shù)據(jù)傳輸了。

可以通過Socket編程在設(shè)備之間建立連接,并傳輸文件或其他數(shù)據(jù)。

根據(jù)應(yīng)用需求,可以創(chuàng)建服務(wù)端套接字監(jiān)聽客戶端的連接請求,也可以作為客戶端主動連接到服務(wù)端。

7.「數(shù)據(jù)傳輸完成與斷開連接」:

數(shù)據(jù)傳輸完成后,應(yīng)用需要適當(dāng)?shù)仃P(guān)閉套接字和斷開Wi-Fi P2P連接。

使用WifiP2pManager的相關(guān)方法來斷開連接,并釋放相關(guān)資源。

責(zé)任編輯:武曉燕 來源: 沐雨花飛蝶
相關(guān)推薦

2024-08-06 14:03:35

2012-12-10 09:46:21

P2P云存儲Symform

2009-04-07 10:39:13

2009-05-18 09:11:00

IPTV融合寬帶

2011-11-17 16:58:11

AndroidAdobeAIR

2010-03-22 15:27:40

云計算

2020-03-05 20:30:15

Syncthing文件同步工具開源

2010-07-13 14:41:14

2022-07-19 16:59:04

流媒體傳輸IPC物聯(lián)網(wǎng)

2023-03-14 12:43:57

2011-12-19 09:46:31

2010-10-29 09:43:50

Wi-Fi DirecWi-Fi聯(lián)

2010-03-10 10:51:30

2017-11-20 17:53:00

阿里開源容器

2010-06-28 11:15:45

BitTorrent協(xié)

2012-09-25 13:47:43

C#網(wǎng)絡(luò)協(xié)議P2P

2015-04-27 11:49:23

2018-08-16 07:29:02

2013-03-13 09:24:56

2010-07-07 10:31:45

點贊
收藏

51CTO技術(shù)棧公眾號