網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
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)閉連接,那我們就可以將這些他們共有的部分抽象出來(lái)給應(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語(yǔ)言中的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)方法來(lá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)UDP
與TCPClient
這兩個(gè)類,他們都實(shí)現(xiàn)了Communicate
接口。
我沒有實(shí)現(xiàn)TCPServer,已經(jīng)實(shí)現(xiàn)的兩種具體實(shí)現(xiàn)可以參考我的gitee倉(cāng)庫(kù)
實(shí)現(xiàn)應(yīng)用層
這樣一來(lái)在應(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)用部分就更不用說(shuō)了,完全不需要修改。這樣一來(lái)當(dāng)我們需要修改當(dāng)前通信方式時(shí)只需要將Communicate.UDP
改為Communicate.TCPClient
,極大地降低了后續(xù)修改的工作量。
總結(jié)
實(shí)現(xiàn)了統(tǒng)一接口之后確實(shí)可以使后續(xù)修改實(shí)現(xiàn)更加方便,程序結(jié)構(gòu)也更加工程化。
原文鏈接:https://www.cnblogs.com/xuankaicat/archive/2021/12/08/15663807.html
相關(guān)推薦
- 2024-07-15 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- 2022-07-15 C++面向?qū)ο笾惡蛯?duì)象那些你不知道的細(xì)節(jié)原理詳解_C 語(yǔ)言
- 2022-06-14 jquery實(shí)現(xiàn)點(diǎn)擊按鈕顯示與隱藏效果_jquery
- 2022-11-05 Rust使用libloader調(diào)用動(dòng)態(tài)鏈接庫(kù)_Rust語(yǔ)言
- 2022-08-10 go?字符串修改的操作代碼_Golang
- 2022-09-18 iOS開發(fā)技能weak和strong修飾符的規(guī)范使用詳解_IOS
- 2022-04-17 新版本VS Code 終端設(shè)置為git bash
- 2022-05-13 C++ OpenCV cv::Mat 矩陣操作
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支