Kotlin + Netty 在 Android 上实现 Socket 的服务端

一. 背景

最近的一个项目:需要使用 Android App 作为 Socket 的服务端,并且一个端口能够同时监听 TCP/Web Socket 协议。

自然而然,项目决定采用 Netty 框架。Netty 服务端在收到客户端发来的消息后,能够做出相应的业务处理。在某些场景下,服务端也需要给客户端 App/网页发送消息。

二. Netty 的使用

2.1 Netty 服务端

首先,定义好 NettyServer,它使用 object声明表示是一个单例。用于 Netty 服务端的启动、关闭以及发送消息。


   
   
   
  1. object NettyServer {

  2. private val TAG = "NettyServer"

  3. private var channel: Channel?=null

  4. private lateinit var listener: NettyServerListener<String>

  5. private lateinit var bossGroup: EventLoopGroup

  6. private lateinit var workerGroup: EventLoopGroup

  7. var port = 8888

  8. set(value) {

  9. field = value

  10. }

  11. var webSocketPath = "/ws"

  12. set(value) {

  13. field = value

  14. }

  15. var isServerStart: Boolean = false

  16. private set

  17. fun start() {

  18. object : Thread() {

  19. override fun run() {

  20. super.run()

  21. bossGroup = NioEventLoopGroup(1)

  22. workerGroup = NioEventLoopGroup()

  23. try {

  24. val b = ServerBootstrap()

  25. b.group(bossGroup, workerGroup)

  26. .channel(NioServerSocketChannel::class.java)

  27. .localAddress(InetSocketAddress(port))

  28. .childOption(ChannelOption.SO_KEEPALIVE, true)

  29. .childOption(ChannelOption.SO_REUSEADDR, true)

  30. .childOption(ChannelOption.TCP_NODELAY, true)

  31. .childHandler(NettyServerInitializer(listener,webSocketPath))

  32. // Bind and start to accept incoming connections.

  33. val f = b.bind().sync()

  34. Log.i(TAG, NettyServer::class.java.name + " started and listen on " + f.channel().localAddress())

  35. isServerStart = true

  36. listener.onStartServer()

  37. f.channel().closeFuture().sync()

  38. } catch (e: Exception) {

  39. Log.e(TAG, e.localizedMessage)

  40. e.printStackTrace()

  41. } finally {

  42. isServerStart = false

  43. listener.onStopServer()

  44. disconnect()

  45. }

  46. }

  47. }.start()

  48. }

  49. fun disconnect() {

  50. workerGroup.shutdownGracefully()

  51. bossGroup.shutdownGracefully()

  52. }

  53. fun setListener(listener: NettyServerListener<String>) {

  54. this.listener = listener

  55. }

  56. // 异步发送TCP消息

  57. fun sendMsgToClient(data: String, listener: ChannelFutureListener) = channel?.run {

  58. val flag = this.isActive

  59. if (flag) {

  60. this.writeAndFlush(data + System.getProperty("line.separator")).addListener(listener)

  61. }

  62. flag

  63. } ?: false

  64. // 同步发送TCP消息

  65. fun sendMsgToClient(data: String) = channel?.run {

  66. if (this.isActive) {

  67. return this.writeAndFlush(data + System.getProperty("line.separator")).awaitUninterruptibly().isSuccess

  68. }

  69. false

  70. } ?: false

  71. // 异步发送WebSocket消息

  72. fun sendMsgToWS(data: String,listener: ChannelFutureListener) = channel?.run {

  73. val flag = this.isActive

  74. if (flag) {

  75. this.writeAndFlush(TextWebSocketFrame(data)).addListener(listener)

  76. }

  77. flag

  78. } ?: false

  79. // 同步发送TCP消息

  80. fun sendMsgToWS(data: String) = channel?.run {

  81. if (this.isActive) {

  82. return this.writeAndFlush(TextWebSocketFrame(data)).awaitUninterruptibly().isSuccess

  83. }

  84. false

  85. } ?: false

  86. /**

  87. * 切换通道

  88. * 设置服务端,与哪个客户端通信

  89. * @param channel

  90. */

  91. fun selectorChannel(channel: Channel?) {

  92. this.channel = channel

  93. }

  94. }

NettyServerInitializer 是服务端跟客户端连接之后使用的 childHandler:


   
   
   
  1. class NettyServerInitializer(private val mListener: NettyServerListener<String>,private val webSocketPath:String) : ChannelInitializer<SocketChannel>() {

  2. @Throws(Exception::class)

  3. public override fun initChannel(ch: SocketChannel) {

  4. val pipeline = ch.pipeline()

  5. pipeline.addLast("active",ChannelActiveHandler(mListener))

  6. pipeline.addLast("socketChoose", SocketChooseHandler(webSocketPath))

  7. pipeline.addLast("string_encoder",StringEncoder(CharsetUtil.UTF_8))

  8. pipeline.addLast("linebased",LineBasedFrameDecoder(1024))

  9. pipeline.addLast("string_decoder",StringDecoder(CharsetUtil.UTF_8))

  10. pipeline.addLast("commonhandler", CustomerServerHandler(mListener))

  11. }

  12. }

NettyServerInitializer 包含了多个 Handler:连接使用的ChannelActiveHandler,协议选择使用的 SocketChooseHandler,TCP 消息使用的 StringEncoder、LineBasedFrameDecoder、StringDecoder&#

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值