溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Android如何實(shí)現(xiàn)socket通信統(tǒng)一接口

發(fā)布時(shí)間:2021-12-13 09:13:32 來源:億速云 閱讀:151 作者:小新 欄目:開發(fā)技術(shù)

小編給大家分享一下Android如何實(shí)現(xiàn)socket通信統(tǒng)一接口,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

    Android實(shí)現(xiàn)socket通信統(tǒng)一接口,統(tǒng)一接口之后可以在不需要大量修改應(yīng)用層代碼的情況下,使用與當(dāng)前功能類似但是底層實(shí)現(xiàn)不同的功能,以實(shí)現(xiàn)的UDP與TCP兩種通信方式的接口為例。

    UDP通信與TCP通信的實(shí)現(xiàn)

    UDP通信

    我們?cè)谑褂肬DP通信方式時(shí),我們會(huì)這樣實(shí)現(xiàn)

    //設(shè)置socket
    val socket = DatagramSocket()
    val serverPort = 9000
    val address = InetAddress.getByName("ip地址")
    //發(fā)送
    val bytes = message.toByteArray(Charsets.UTF_8)
    val len = bytes.size
    val sendPacket = DatagramPacket(bytes, len, address, serverPort)
    socket.send(sendPacket)
    //接收
    socket.receive(receivePacket)
    val data = String(receivePacket.data, Charsets.UTF_8)
    //處理接收到的數(shù)據(jù)
    //關(guān)閉連接
    socket.close()

    TCP客戶端通信

    我們?cè)谑褂肨CP客戶端通信方式時(shí),我們會(huì)這樣實(shí)現(xiàn)

    //設(shè)置socket
    val serverPort = 9000
    val address = InetAddress.getByName("ip地址")
    val socket = Socket(address, serverPort)
    val input = socket.getInputStream()
    val output = socket.getOutputStream()
    //發(fā)送
    output.write(message.toByteArray(Charsets.UTF_8))
    //接收
    val len = input.read(receive)
    val data = String(receive, 0, len, Charsets.UTF_8)
    //處理接收到的數(shù)據(jù)
    //關(guān)閉連接
    socket.close()

    這樣的話,如果我們需要將應(yīng)用層中的UDP連接轉(zhuǎn)換為TCP連接,就要大量地修改代碼。

    使用統(tǒng)一接口

    統(tǒng)一接口之后可以在不需要大量修改應(yīng)用層代碼的情況下,使用與當(dāng)前功能類似但是底層實(shí)現(xiàn)不同的功能。

    以之前我們實(shí)現(xiàn)的UDP與TCP兩種通信方式為例,要將其中任意一種轉(zhuǎn)換為另一種時(shí),又或者有新的通信方式需要采用,每次都繁復(fù)地修改應(yīng)用層代碼很明顯不是個(gè)好主意。

    我們可以簡(jiǎn)單地分析一下這兩種通信方式,他們都要經(jīng)歷初始化(設(shè)置socket)-> 發(fā)送或者接收 -> 處理數(shù)據(jù) -> 關(guān)閉連接,那我們就可以將這些他們共有的部分抽象出來給應(yīng)用層使用。

    定義接口

    新建一個(gè)Communicate.kt文件,實(shí)現(xiàn)Communicate接口

    interface Communicate {
        /**
         * 通信端口
         */
        var serverPort: Int
        /**
         * 通信地址
         */
        var address: String
        /**
         * 輸入編碼
         */
        var inCharset: Charset
        /**
         * 輸出編碼
         */
        var outCharset: Charset
        /**
         * 發(fā)送數(shù)據(jù)
         * @param message 數(shù)據(jù)內(nèi)容
         */
        fun send(message: String)
        /**
         * 開始接收數(shù)據(jù)
         * @param onReceive 處理接收到的數(shù)據(jù)的函數(shù),函數(shù)返回值為是否繼續(xù)接收消息.
         * 請(qǐng)不要在函數(shù)中使用stopReceive()函數(shù)停止接收數(shù)據(jù),這不會(huì)起作用。
         * @return 是否開啟成功
         */
        fun startReceive(onReceive: OnReceiveFunc): Boolean
        /**
         * 停止接收數(shù)據(jù)
         */
        fun stopReceive()
        /**
         * 開啟通信,用于TCP建立連接
         * @return 是否開啟成功
         */
        fun open(): Boolean
        /**
         * 關(guān)閉通信
         */
        fun close()
    }

    上面的代碼塊中還用到了OnReceiveFunc,這用到了kotlin中的類型映射,類似于c語言中的typedef,下面是OnReceiveFunc的實(shí)現(xiàn),他接收一個(gè)字符串作為參數(shù),返回一個(gè)布爾型變量。

    typealias OnReceiveFunc = (String) -> Boolean

    在具體使用時(shí)利用kotlin的特性,可以直接寫OnReceiveFunc方法體。

    communicate.startReceive {
        binding.textView.text = it
        return@startReceive false
    }

    而在java中的使用方法如下

    communicate.startReceive(result -> {
        binding.textView.setText(result);
        return false;
    });

    注:這里的communicate是一個(gè)實(shí)現(xiàn)了Communicate接口的通信對(duì)象,而我們并沒有關(guān)心到底采用了什么通信方式。

    這部分中我們可以使用靜態(tài)方法來讓應(yīng)用層創(chuàng)建對(duì)象(即選擇想要的連接方式)更加方便。

    interface Communicate {
     companion object {
         @JvmStatic
         val TCPClient: Communicate
             get() = TCP()
         @JvmStatic
         val UDP: Communicate
             get() = UDP()
     }
     //其他代碼
    }

    其中用到了@JvmStatic的注解,這讓java調(diào)用Communicate時(shí)可以少一層companion。

    實(shí)現(xiàn)接口

    我們?cè)賹?shí)現(xiàn)UDPTCPClient這兩個(gè)類,他們都實(shí)現(xiàn)了Communicate接口。

    我沒有實(shí)現(xiàn)TCPServer,已經(jīng)實(shí)現(xiàn)的兩種具體實(shí)現(xiàn)可以參考我的gitee倉庫

    實(shí)現(xiàn)應(yīng)用層

    這樣一來在應(yīng)用層調(diào)用就可以使用同一種風(fēng)格,比如聲明一個(gè)UDP通信對(duì)象

    private val communicate = Communicate.UDP.apply {
        address = "ip地址"
        serverPort = 9000
        inCharset = Charset.forName("gb2312")
        outCharset = Charset.forName("gb2312")
        open()
    }

    而聲明一個(gè)TCPClient通信對(duì)象只需要這樣

    private val communicate = Communicate.TCPClient.apply {
        //與UDP完全一樣
    }

    而調(diào)用部分就更不用說了,完全不需要修改。這樣一來當(dāng)我們需要修改當(dāng)前通信方式時(shí)只需要將Communicate.UDP改為Communicate.TCPClient,極大地降低了后續(xù)修改的工作量。

    看完了這篇文章,相信你對(duì)“Android如何實(shí)現(xiàn)socket通信統(tǒng)一接口”有了一定的了解,如果想了解更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI