经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » Android » 查看文章
Android实现socket通信统一接口
来源:cnblogs  作者:轩恺  时间:2021/12/15 8:47:35  对本文有异议

UDP通信与TCP通信的实现

UDP通信

我们在使用UDP通信方式时,我们会这样实现

  1. //设置socket
  2. val socket = DatagramSocket()
  3. val serverPort = 9000
  4. val address = InetAddress.getByName("ip地址")
  5. //发送
  6. val bytes = message.toByteArray(Charsets.UTF_8)
  7. val len = bytes.size
  8. val sendPacket = DatagramPacket(bytes, len, address, serverPort)
  9. socket.send(sendPacket)
  10. //接收
  11. socket.receive(receivePacket)
  12. val data = String(receivePacket.data, Charsets.UTF_8)
  13. //处理接收到的数据
  14. //关闭连接
  15. socket.close()

TCP客户端通信

我们在使用TCP客户端通信方式时,我们会这样实现

  1. //设置socket
  2. val serverPort = 9000
  3. val address = InetAddress.getByName("ip地址")
  4. val socket = Socket(address, serverPort)
  5. val input = socket.getInputStream()
  6. val output = socket.getOutputStream()
  7. //发送
  8. output.write(message.toByteArray(Charsets.UTF_8))
  9. //接收
  10. val len = input.read(receive)
  11. val data = String(receive, 0, len, Charsets.UTF_8)
  12. //处理接收到的数据
  13. //关闭连接
  14. socket.close()

这样的话,如果我们需要将应用层中的UDP连接转换为TCP连接,就要大量地修改代码。

使用统一接口

统一接口之后可以在不需要大量修改应用层代码的情况下,使用与当前功能类似但是底层实现不同的功能。

以之前我们实现的UDP与TCP两种通信方式为例,要将其中任意一种转换为另一种时,又或者有新的通信方式需要采用,每次都繁复地修改应用层代码很明显不是个好主意。

我们可以简单地分析一下这两种通信方式,他们都要经历初始化(设置socket)-> 发送或者接收 -> 处理数据 -> 关闭连接,那我们就可以将这些他们共有的部分抽象出来给应用层使用。

定义接口

新建一个Communicate.kt文件,实现Communicate接口

  1. interface Communicate {
  2. /**
  3. * 通信端口
  4. */
  5. var serverPort: Int
  6. /**
  7. * 通信地址
  8. */
  9. var address: String
  10. /**
  11. * 输入编码
  12. */
  13. var inCharset: Charset
  14. /**
  15. * 输出编码
  16. */
  17. var outCharset: Charset
  18. /**
  19. * 发送数据
  20. * @param message 数据内容
  21. */
  22. fun send(message: String)
  23. /**
  24. * 开始接收数据
  25. * @param onReceive 处理接收到的数据的函数,函数返回值为是否继续接收消息.
  26. * 请不要在函数中使用stopReceive()函数停止接收数据,这不会起作用。
  27. * @return 是否开启成功
  28. */
  29. fun startReceive(onReceive: OnReceiveFunc): Boolean
  30. /**
  31. * 停止接收数据
  32. */
  33. fun stopReceive()
  34. /**
  35. * 开启通信,用于TCP建立连接
  36. * @return 是否开启成功
  37. */
  38. fun open(): Boolean
  39. /**
  40. * 关闭通信
  41. */
  42. fun close()
  43. }

上面的代码块中还用到了OnReceiveFunc,这用到了kotlin中的类型映射,类似于c语言中的typedef,下面是OnReceiveFunc的实现,他接收一个字符串作为参数,返回一个布尔型变量。

  1. typealias OnReceiveFunc = (String) -> Boolean

在具体使用时利用kotlin的特性,可以直接写OnReceiveFunc方法体。

  1. communicate.startReceive {
  2. binding.textView.text = it
  3. return@startReceive false
  4. }

而在java中的使用方法如下

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

注:这里的communicate是一个实现了Communicate接口的通信对象,而我们并没有关心到底采用了什么通信方式。

这部分中我们可以使用静态方法来让应用层创建对象(即选择想要的连接方式)更加方便。

  1. interface Communicate {
  2. companion object {
  3. @JvmStatic
  4. val TCPClient: Communicate
  5. get() = TCP()
  6. @JvmStatic
  7. val UDP: Communicate
  8. get() = UDP()
  9. }
  10. //其他代码
  11. }

其中用到了@JvmStatic的注解,这让java调用Communicate时可以少一层companion

实现接口

我们再实现UDPTCPClient这两个类,他们都实现了Communicate接口。

我没有实现TCPServer,已经实现的两种具体实现可以参考我的gitee仓库

实现应用层

这样一来在应用层调用就可以使用同一种风格,比如声明一个UDP通信对象

  1. private val communicate = Communicate.UDP.apply {
  2. address = "ip地址"
  3. serverPort = 9000
  4. inCharset = Charset.forName("gb2312")
  5. outCharset = Charset.forName("gb2312")
  6. open()
  7. }

而声明一个TCPClient通信对象只需要这样

  1. private val communicate = Communicate.TCPClient.apply {
  2. //与UDP完全一样
  3. }

而调用部分就更不用说了,完全不需要修改。这样一来当我们需要修改当前通信方式时只需要将Communicate.UDP改为Communicate.TCPClient,极大地降低了后续修改的工作量。

总结

实现了统一接口之后确实可以使后续修改实现更加方便,程序结构也更加工程化。

原文链接:http://www.cnblogs.com/xuankaicat/p/15663807.html

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号