Android實現socket通信統一接口的方法

Android實現socket通信統一接口,統一接口之後可以在不需要大量修改應用層代碼的情況下,使用與當前功能類似但是底層實現不同的功能,以實現的UDP與TCP兩種通信方式的接口為例。

UDP通信與TCP通信的實現

UDP通信

我們在使用UDP通信方式時,我們會這樣實現

//設置socket
val socket = DatagramSocket()
val serverPort = 9000
val address = InetAddress.getByName("ip地址")
//發送
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)
//處理接收到的數據
//關閉連接
socket.close()

TCP客戶端通信

我們在使用TCP客戶端通信方式時,我們會這樣實現

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

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

使用統一接口

統一接口之後可以在不需要大量修改應用層代碼的情況下,使用與當前功能類似但是底層實現不同的功能。

以之前我們實現的UDP與TCP兩種通信方式為例,要將其中任意一種轉換為另一種時,又或者有新的通信方式需要采用,每次都繁復地修改應用層代碼很明顯不是個好主意。

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

定義接口

新建一個Communicate.kt文件,實現Communicate接口

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

上面的代碼塊中還用到瞭OnReceiveFunc,這用到瞭kotlin中的類型映射,類似於c語言中的typedef,下面是OnReceiveFunc的實現,他接收一個字符串作為參數,返回一個佈爾型變量。

typealias OnReceiveFunc = (String) -> Boolean

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

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

而在java中的使用方法如下

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

註:這裡的communicate是一個實現瞭Communicate接口的通信對象,而我們並沒有關心到底采用瞭什麼通信方式。

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

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

其中用到瞭@JvmStatic的註解,這讓java調用Communicate時可以少一層companion

實現接口

我們再實現UDPTCPClient這兩個類,他們都實現瞭Communicate接口。

我沒有實現TCPServer,已經實現的兩種具體實現可以參考我的gitee倉庫

實現應用層

這樣一來在應用層調用就可以使用同一種風格,比如聲明一個UDP通信對象

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

而聲明一個TCPClient通信對象隻需要這樣

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

而調用部分就更不用說瞭,完全不需要修改。這樣一來當我們需要修改當前通信方式時隻需要將Communicate.UDP改為Communicate.TCPClient,極大地降低瞭後續修改的工作量。

總結

實現瞭統一接口之後確實可以使後續修改實現更加方便,程序結構也更加工程化。

到此這篇關於Android實現socket通信統一接口 的文章就介紹到這瞭,更多相關Android socket通信內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: