diff --git a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt index 1db4e7c..f50c0f7 100644 --- a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt @@ -34,4 +34,5 @@ const val WIFI_PASSWORD = "zhsz20311hw" const val UDP_HOST = "udpServer" const val UDP_PORT = 9000 + const val TCP_PORT = 9000 } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt index 1db4e7c..f50c0f7 100644 --- a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt @@ -34,4 +34,5 @@ const val WIFI_PASSWORD = "zhsz20311hw" const val UDP_HOST = "udpServer" const val UDP_PORT = 9000 + const val TCP_PORT = 9000 } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt deleted file mode 100644 index a7f9d27..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelHandlerContext -import io.netty.channel.SimpleChannelInboundHandler -import io.netty.channel.socket.DatagramPacket -import io.netty.util.CharsetUtil - - -abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() { - - private var handlerContext: ChannelHandlerContext? = null - - override fun channelActive(ctx: ChannelHandlerContext?) { - super.channelActive(ctx) - handlerContext = ctx - } - - override fun channelInactive(ctx: ChannelHandlerContext?) { - super.channelInactive(ctx) - handlerContext?.close() - } - - fun sendDatagramPacket(obj: Any) { - handlerContext?.writeAndFlush(obj) - } - - fun releasePort() { - handlerContext?.close() - } - - override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) { - receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8)) - } - - abstract fun receivedMessage(data: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt index 1db4e7c..f50c0f7 100644 --- a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt @@ -34,4 +34,5 @@ const val WIFI_PASSWORD = "zhsz20311hw" const val UDP_HOST = "udpServer" const val UDP_PORT = 9000 + const val TCP_PORT = 9000 } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt deleted file mode 100644 index a7f9d27..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelHandlerContext -import io.netty.channel.SimpleChannelInboundHandler -import io.netty.channel.socket.DatagramPacket -import io.netty.util.CharsetUtil - - -abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() { - - private var handlerContext: ChannelHandlerContext? = null - - override fun channelActive(ctx: ChannelHandlerContext?) { - super.channelActive(ctx) - handlerContext = ctx - } - - override fun channelInactive(ctx: ChannelHandlerContext?) { - super.channelInactive(ctx) - handlerContext?.close() - } - - fun sendDatagramPacket(obj: Any) { - handlerContext?.writeAndFlush(obj) - } - - fun releasePort() { - handlerContext?.close() - } - - override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) { - receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8)) - } - - abstract fun receivedMessage(data: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt deleted file mode 100644 index bcdeef1..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelInitializer -import io.netty.channel.socket.DatagramChannel -import io.netty.handler.timeout.IdleStateHandler - - -open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) : - ChannelInitializer() { - - override fun initChannel(datagramChannel: DatagramChannel) { - val pipeline = datagramChannel.pipeline() - pipeline.addLast( - IdleStateHandler(12, 15, 0) - ).addLast(handler) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt index 1db4e7c..f50c0f7 100644 --- a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt @@ -34,4 +34,5 @@ const val WIFI_PASSWORD = "zhsz20311hw" const val UDP_HOST = "udpServer" const val UDP_PORT = 9000 + const val TCP_PORT = 9000 } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt deleted file mode 100644 index a7f9d27..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelHandlerContext -import io.netty.channel.SimpleChannelInboundHandler -import io.netty.channel.socket.DatagramPacket -import io.netty.util.CharsetUtil - - -abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() { - - private var handlerContext: ChannelHandlerContext? = null - - override fun channelActive(ctx: ChannelHandlerContext?) { - super.channelActive(ctx) - handlerContext = ctx - } - - override fun channelInactive(ctx: ChannelHandlerContext?) { - super.channelInactive(ctx) - handlerContext?.close() - } - - fun sendDatagramPacket(obj: Any) { - handlerContext?.writeAndFlush(obj) - } - - fun releasePort() { - handlerContext?.close() - } - - override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) { - receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8)) - } - - abstract fun receivedMessage(data: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt deleted file mode 100644 index bcdeef1..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelInitializer -import io.netty.channel.socket.DatagramChannel -import io.netty.handler.timeout.IdleStateHandler - - -open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) : - ChannelInitializer() { - - override fun initChannel(datagramChannel: DatagramChannel) { - val pipeline = datagramChannel.pipeline() - pipeline.addLast( - IdleStateHandler(12, 15, 0) - ).addLast(handler) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt deleted file mode 100644 index 183945a..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt +++ /dev/null @@ -1,101 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import com.casic.br.operationsite.utils.LocaleConstant -import com.pengxh.kt.lite.utils.SaveKeyValues -import io.netty.bootstrap.Bootstrap -import io.netty.buffer.ByteBuf -import io.netty.buffer.Unpooled -import io.netty.channel.ChannelFuture -import io.netty.channel.ChannelOption -import io.netty.channel.nio.NioEventLoopGroup -import io.netty.channel.socket.DatagramPacket -import io.netty.channel.socket.nio.NioDatagramChannel -import io.netty.util.CharsetUtil -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import java.net.InetSocketAddress -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors - - -class UdpClient : UdpChannelInboundHandler(), Runnable { - - private val bootStrap by lazy { Bootstrap() } - private val eventLoopGroup by lazy { NioEventLoopGroup() } - private val udpChannelInitializer by lazy { UdpChannelInitializer(this) } - private var executorService: ExecutorService - - init { - bootStrap.group(eventLoopGroup) - bootStrap.channel(NioDatagramChannel::class.java) - .option(ChannelOption.SO_RCVBUF, 1024) - .option(ChannelOption.SO_SNDBUF, 1024) - bootStrap.handler(udpChannelInitializer) - - executorService = Executors.newSingleThreadExecutor() - executorService.execute(this) - } - - override fun run() { - try { - val channelFuture: ChannelFuture = bootStrap.bind(LocaleConstant.UDP_PORT).sync() - channelFuture.channel().closeFuture().sync() - } catch (e: InterruptedException) { - e.printStackTrace() - } finally { - eventLoopGroup.shutdownGracefully() - } - } - - fun send(value: String) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value, CharsetUtil.UTF_8), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteArray) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteBuf) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun release() { - releasePort() - } - - override fun receivedMessage(data: String) { - - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt index 1db4e7c..f50c0f7 100644 --- a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt @@ -34,4 +34,5 @@ const val WIFI_PASSWORD = "zhsz20311hw" const val UDP_HOST = "udpServer" const val UDP_PORT = 9000 + const val TCP_PORT = 9000 } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt deleted file mode 100644 index a7f9d27..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelHandlerContext -import io.netty.channel.SimpleChannelInboundHandler -import io.netty.channel.socket.DatagramPacket -import io.netty.util.CharsetUtil - - -abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() { - - private var handlerContext: ChannelHandlerContext? = null - - override fun channelActive(ctx: ChannelHandlerContext?) { - super.channelActive(ctx) - handlerContext = ctx - } - - override fun channelInactive(ctx: ChannelHandlerContext?) { - super.channelInactive(ctx) - handlerContext?.close() - } - - fun sendDatagramPacket(obj: Any) { - handlerContext?.writeAndFlush(obj) - } - - fun releasePort() { - handlerContext?.close() - } - - override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) { - receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8)) - } - - abstract fun receivedMessage(data: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt deleted file mode 100644 index bcdeef1..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelInitializer -import io.netty.channel.socket.DatagramChannel -import io.netty.handler.timeout.IdleStateHandler - - -open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) : - ChannelInitializer() { - - override fun initChannel(datagramChannel: DatagramChannel) { - val pipeline = datagramChannel.pipeline() - pipeline.addLast( - IdleStateHandler(12, 15, 0) - ).addLast(handler) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt deleted file mode 100644 index 183945a..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt +++ /dev/null @@ -1,101 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import com.casic.br.operationsite.utils.LocaleConstant -import com.pengxh.kt.lite.utils.SaveKeyValues -import io.netty.bootstrap.Bootstrap -import io.netty.buffer.ByteBuf -import io.netty.buffer.Unpooled -import io.netty.channel.ChannelFuture -import io.netty.channel.ChannelOption -import io.netty.channel.nio.NioEventLoopGroup -import io.netty.channel.socket.DatagramPacket -import io.netty.channel.socket.nio.NioDatagramChannel -import io.netty.util.CharsetUtil -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import java.net.InetSocketAddress -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors - - -class UdpClient : UdpChannelInboundHandler(), Runnable { - - private val bootStrap by lazy { Bootstrap() } - private val eventLoopGroup by lazy { NioEventLoopGroup() } - private val udpChannelInitializer by lazy { UdpChannelInitializer(this) } - private var executorService: ExecutorService - - init { - bootStrap.group(eventLoopGroup) - bootStrap.channel(NioDatagramChannel::class.java) - .option(ChannelOption.SO_RCVBUF, 1024) - .option(ChannelOption.SO_SNDBUF, 1024) - bootStrap.handler(udpChannelInitializer) - - executorService = Executors.newSingleThreadExecutor() - executorService.execute(this) - } - - override fun run() { - try { - val channelFuture: ChannelFuture = bootStrap.bind(LocaleConstant.UDP_PORT).sync() - channelFuture.channel().closeFuture().sync() - } catch (e: InterruptedException) { - e.printStackTrace() - } finally { - eventLoopGroup.shutdownGracefully() - } - } - - fun send(value: String) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value, CharsetUtil.UTF_8), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteArray) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteBuf) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun release() { - releasePort() - } - - override fun receivedMessage(data: String) { - - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt new file mode 100644 index 0000000..0acb367 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt @@ -0,0 +1,19 @@ +package com.casic.br.operationsite.utils.netty.tcp + +interface ISocketListener { + companion object { + const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功 + const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接 + const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败 + } + + /** + * 当接收到系统消息 + */ + fun onMessageResponse(data: ByteArray?) + + /** + * 当连接状态发生变化时调用 + */ + fun onServiceStatusConnectChanged(statusCode: Byte) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt index 1db4e7c..f50c0f7 100644 --- a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt @@ -34,4 +34,5 @@ const val WIFI_PASSWORD = "zhsz20311hw" const val UDP_HOST = "udpServer" const val UDP_PORT = 9000 + const val TCP_PORT = 9000 } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt deleted file mode 100644 index a7f9d27..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelHandlerContext -import io.netty.channel.SimpleChannelInboundHandler -import io.netty.channel.socket.DatagramPacket -import io.netty.util.CharsetUtil - - -abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() { - - private var handlerContext: ChannelHandlerContext? = null - - override fun channelActive(ctx: ChannelHandlerContext?) { - super.channelActive(ctx) - handlerContext = ctx - } - - override fun channelInactive(ctx: ChannelHandlerContext?) { - super.channelInactive(ctx) - handlerContext?.close() - } - - fun sendDatagramPacket(obj: Any) { - handlerContext?.writeAndFlush(obj) - } - - fun releasePort() { - handlerContext?.close() - } - - override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) { - receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8)) - } - - abstract fun receivedMessage(data: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt deleted file mode 100644 index bcdeef1..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelInitializer -import io.netty.channel.socket.DatagramChannel -import io.netty.handler.timeout.IdleStateHandler - - -open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) : - ChannelInitializer() { - - override fun initChannel(datagramChannel: DatagramChannel) { - val pipeline = datagramChannel.pipeline() - pipeline.addLast( - IdleStateHandler(12, 15, 0) - ).addLast(handler) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt deleted file mode 100644 index 183945a..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt +++ /dev/null @@ -1,101 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import com.casic.br.operationsite.utils.LocaleConstant -import com.pengxh.kt.lite.utils.SaveKeyValues -import io.netty.bootstrap.Bootstrap -import io.netty.buffer.ByteBuf -import io.netty.buffer.Unpooled -import io.netty.channel.ChannelFuture -import io.netty.channel.ChannelOption -import io.netty.channel.nio.NioEventLoopGroup -import io.netty.channel.socket.DatagramPacket -import io.netty.channel.socket.nio.NioDatagramChannel -import io.netty.util.CharsetUtil -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import java.net.InetSocketAddress -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors - - -class UdpClient : UdpChannelInboundHandler(), Runnable { - - private val bootStrap by lazy { Bootstrap() } - private val eventLoopGroup by lazy { NioEventLoopGroup() } - private val udpChannelInitializer by lazy { UdpChannelInitializer(this) } - private var executorService: ExecutorService - - init { - bootStrap.group(eventLoopGroup) - bootStrap.channel(NioDatagramChannel::class.java) - .option(ChannelOption.SO_RCVBUF, 1024) - .option(ChannelOption.SO_SNDBUF, 1024) - bootStrap.handler(udpChannelInitializer) - - executorService = Executors.newSingleThreadExecutor() - executorService.execute(this) - } - - override fun run() { - try { - val channelFuture: ChannelFuture = bootStrap.bind(LocaleConstant.UDP_PORT).sync() - channelFuture.channel().closeFuture().sync() - } catch (e: InterruptedException) { - e.printStackTrace() - } finally { - eventLoopGroup.shutdownGracefully() - } - } - - fun send(value: String) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value, CharsetUtil.UTF_8), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteArray) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteBuf) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun release() { - releasePort() - } - - override fun receivedMessage(data: String) { - - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt new file mode 100644 index 0000000..0acb367 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt @@ -0,0 +1,19 @@ +package com.casic.br.operationsite.utils.netty.tcp + +interface ISocketListener { + companion object { + const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功 + const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接 + const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败 + } + + /** + * 当接收到系统消息 + */ + fun onMessageResponse(data: ByteArray?) + + /** + * 当连接状态发生变化时调用 + */ + fun onServiceStatusConnectChanged(statusCode: Byte) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt new file mode 100644 index 0000000..d381ce0 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt @@ -0,0 +1,34 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.util.Log +import io.netty.channel.ChannelHandlerContext +import io.netty.channel.SimpleChannelInboundHandler + +class SocketChannelHandle(private val listener: ISocketListener?) : + SimpleChannelInboundHandler() { + + private val kTag = "SocketChannelHandle" + + override fun channelActive(ctx: ChannelHandlerContext) { + super.channelActive(ctx) + Log.d(kTag, "channelActive ===> 连接成功") + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS) + } + + override fun channelInactive(ctx: ChannelHandlerContext) { + super.channelInactive(ctx) + Log.e(kTag, "channelInactive: 连接断开") + } + + override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) { + listener?.onMessageResponse(data) + } + + override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) { + super.exceptionCaught(ctx, cause) + Log.d(kTag, "exceptionCaught ===> $cause") + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR) + cause.printStackTrace() + ctx.close() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt index 1db4e7c..f50c0f7 100644 --- a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt @@ -34,4 +34,5 @@ const val WIFI_PASSWORD = "zhsz20311hw" const val UDP_HOST = "udpServer" const val UDP_PORT = 9000 + const val TCP_PORT = 9000 } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt deleted file mode 100644 index a7f9d27..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelHandlerContext -import io.netty.channel.SimpleChannelInboundHandler -import io.netty.channel.socket.DatagramPacket -import io.netty.util.CharsetUtil - - -abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() { - - private var handlerContext: ChannelHandlerContext? = null - - override fun channelActive(ctx: ChannelHandlerContext?) { - super.channelActive(ctx) - handlerContext = ctx - } - - override fun channelInactive(ctx: ChannelHandlerContext?) { - super.channelInactive(ctx) - handlerContext?.close() - } - - fun sendDatagramPacket(obj: Any) { - handlerContext?.writeAndFlush(obj) - } - - fun releasePort() { - handlerContext?.close() - } - - override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) { - receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8)) - } - - abstract fun receivedMessage(data: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt deleted file mode 100644 index bcdeef1..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelInitializer -import io.netty.channel.socket.DatagramChannel -import io.netty.handler.timeout.IdleStateHandler - - -open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) : - ChannelInitializer() { - - override fun initChannel(datagramChannel: DatagramChannel) { - val pipeline = datagramChannel.pipeline() - pipeline.addLast( - IdleStateHandler(12, 15, 0) - ).addLast(handler) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt deleted file mode 100644 index 183945a..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt +++ /dev/null @@ -1,101 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import com.casic.br.operationsite.utils.LocaleConstant -import com.pengxh.kt.lite.utils.SaveKeyValues -import io.netty.bootstrap.Bootstrap -import io.netty.buffer.ByteBuf -import io.netty.buffer.Unpooled -import io.netty.channel.ChannelFuture -import io.netty.channel.ChannelOption -import io.netty.channel.nio.NioEventLoopGroup -import io.netty.channel.socket.DatagramPacket -import io.netty.channel.socket.nio.NioDatagramChannel -import io.netty.util.CharsetUtil -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import java.net.InetSocketAddress -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors - - -class UdpClient : UdpChannelInboundHandler(), Runnable { - - private val bootStrap by lazy { Bootstrap() } - private val eventLoopGroup by lazy { NioEventLoopGroup() } - private val udpChannelInitializer by lazy { UdpChannelInitializer(this) } - private var executorService: ExecutorService - - init { - bootStrap.group(eventLoopGroup) - bootStrap.channel(NioDatagramChannel::class.java) - .option(ChannelOption.SO_RCVBUF, 1024) - .option(ChannelOption.SO_SNDBUF, 1024) - bootStrap.handler(udpChannelInitializer) - - executorService = Executors.newSingleThreadExecutor() - executorService.execute(this) - } - - override fun run() { - try { - val channelFuture: ChannelFuture = bootStrap.bind(LocaleConstant.UDP_PORT).sync() - channelFuture.channel().closeFuture().sync() - } catch (e: InterruptedException) { - e.printStackTrace() - } finally { - eventLoopGroup.shutdownGracefully() - } - } - - fun send(value: String) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value, CharsetUtil.UTF_8), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteArray) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteBuf) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun release() { - releasePort() - } - - override fun receivedMessage(data: String) { - - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt new file mode 100644 index 0000000..0acb367 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt @@ -0,0 +1,19 @@ +package com.casic.br.operationsite.utils.netty.tcp + +interface ISocketListener { + companion object { + const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功 + const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接 + const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败 + } + + /** + * 当接收到系统消息 + */ + fun onMessageResponse(data: ByteArray?) + + /** + * 当连接状态发生变化时调用 + */ + fun onServiceStatusConnectChanged(statusCode: Byte) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt new file mode 100644 index 0000000..d381ce0 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt @@ -0,0 +1,34 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.util.Log +import io.netty.channel.ChannelHandlerContext +import io.netty.channel.SimpleChannelInboundHandler + +class SocketChannelHandle(private val listener: ISocketListener?) : + SimpleChannelInboundHandler() { + + private val kTag = "SocketChannelHandle" + + override fun channelActive(ctx: ChannelHandlerContext) { + super.channelActive(ctx) + Log.d(kTag, "channelActive ===> 连接成功") + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS) + } + + override fun channelInactive(ctx: ChannelHandlerContext) { + super.channelInactive(ctx) + Log.e(kTag, "channelInactive: 连接断开") + } + + override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) { + listener?.onMessageResponse(data) + } + + override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) { + super.exceptionCaught(ctx, cause) + Log.d(kTag, "exceptionCaught ===> $cause") + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR) + cause.printStackTrace() + ctx.close() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt new file mode 100644 index 0000000..dffac03 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt @@ -0,0 +1,153 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.os.SystemClock +import android.util.Log +import io.netty.bootstrap.Bootstrap +import io.netty.channel.* +import io.netty.channel.nio.NioEventLoopGroup +import io.netty.channel.socket.SocketChannel +import io.netty.channel.socket.nio.NioSocketChannel +import io.netty.handler.codec.bytes.ByteArrayDecoder +import io.netty.handler.codec.bytes.ByteArrayEncoder +import io.netty.handler.timeout.IdleStateHandler + +class SocketClient { + + private val kTag = "SocketClient" + + private var host: String? = null + private var port = 8000 + private var nioEventLoopGroup: NioEventLoopGroup? = null + private var channel: Channel? = null + private var listener: ISocketListener? = null + + //现在连接的状态 + var connectStatus = false //判断是否已连接 + private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用 + private var isNeedReconnect = true //是否需要重连 + var isConnecting = false //是否正在连接 + private set + private var reconnectIntervalTime: Long = 15000 //重连的时间 + + //重连时间 + fun setReconnectNum(reconnectNum: Int) { + this.reconnectNum = reconnectNum + } + + fun setReconnectIntervalTime(reconnectIntervalTime: Long) { + this.reconnectIntervalTime = reconnectIntervalTime + } + + fun setSocketListener(listener: ISocketListener?) { + this.listener = listener + } + + fun connect(host: String, port: Int) { + this.host = host + this.port = port + Log.d(kTag, "connect ===> 开始连接TCP服务器") + if (isConnecting) { + return + } + //起个线程 + val clientThread: Thread = object : Thread("client-Netty") { + override fun run() { + super.run() + isNeedReconnect = true + reconnectNum = Int.MAX_VALUE + connectServer() + } + } + clientThread.start() + } + + private fun connectServer() { + synchronized(this@SocketClient) { + var channelFuture: ChannelFuture? = null //连接管理对象 + if (!connectStatus) { + isConnecting = true + nioEventLoopGroup = NioEventLoopGroup() //设置的连接group + val bootstrap = Bootstrap() + bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等 + .channel(NioSocketChannel::class.java) + .option(ChannelOption.TCP_NODELAY, true) //无阻塞 + .option(ChannelOption.SO_KEEPALIVE, true) //长连接 + .option( + ChannelOption.RCVBUF_ALLOCATOR, + AdaptiveRecvByteBufAllocator(5000, 5000, 8000) + ) //接收缓冲区 最小值太小时数据接收不全 + .handler(object : ChannelInitializer() { + override fun initChannel(channel: SocketChannel) { + val pipeline = channel.pipeline() + //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调; + //参数2:代表写套接字超时时间,没进行写会触发写超时回调; + //参数3:将在未执行读取或写入时触发超时回调,0代表不处理; + //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接 + pipeline.addLast(IdleStateHandler(60, 10, 0)) + pipeline.addLast(ByteArrayDecoder()) + pipeline.addLast(ByteArrayEncoder()) + pipeline.addLast(SocketChannelHandle(listener)) + } + }) + try { + //连接监听 + channelFuture = bootstrap.connect(host, port) + .addListener(object : ChannelFutureListener { + override fun operationComplete(channelFuture: ChannelFuture) { + if (channelFuture.isSuccess) { + connectStatus = true + channel = channelFuture.channel() + } else { + Log.e(kTag, "operationComplete: 连接失败") + connectStatus = false + } + isConnecting = false + } + }).sync() + // 等待连接关闭 + channelFuture.channel().closeFuture().sync() + } catch (e: Exception) { + e.printStackTrace() + } finally { + connectStatus = false + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识 + if (null != channelFuture) { + if (channelFuture.channel() != null && channelFuture.channel().isOpen) { + channelFuture.channel().close() + } + } + nioEventLoopGroup?.shutdownGracefully() + reconnect() //重新连接 + } + } + } + } + + //断开连接 + fun disconnect() { + Log.d(kTag, "disconnect ===> 断开连接") + isNeedReconnect = false + nioEventLoopGroup?.shutdownGracefully() + } + + //重新连接 + private fun reconnect() { + if (isNeedReconnect && reconnectNum > 0 && !connectStatus) { + reconnectNum-- + SystemClock.sleep(reconnectIntervalTime) + if (isNeedReconnect && reconnectNum > 0 && !connectStatus) { + Log.d(kTag, "reconnect ===> 重新连接") + connectServer() + } + } + } + + fun sendData(bytes: ByteArray) { + channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future -> + if (!future.isSuccess) { + future.channel().close() + nioEventLoopGroup!!.shutdownGracefully() + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt index 1db4e7c..f50c0f7 100644 --- a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt @@ -34,4 +34,5 @@ const val WIFI_PASSWORD = "zhsz20311hw" const val UDP_HOST = "udpServer" const val UDP_PORT = 9000 + const val TCP_PORT = 9000 } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt deleted file mode 100644 index a7f9d27..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelHandlerContext -import io.netty.channel.SimpleChannelInboundHandler -import io.netty.channel.socket.DatagramPacket -import io.netty.util.CharsetUtil - - -abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() { - - private var handlerContext: ChannelHandlerContext? = null - - override fun channelActive(ctx: ChannelHandlerContext?) { - super.channelActive(ctx) - handlerContext = ctx - } - - override fun channelInactive(ctx: ChannelHandlerContext?) { - super.channelInactive(ctx) - handlerContext?.close() - } - - fun sendDatagramPacket(obj: Any) { - handlerContext?.writeAndFlush(obj) - } - - fun releasePort() { - handlerContext?.close() - } - - override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) { - receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8)) - } - - abstract fun receivedMessage(data: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt deleted file mode 100644 index bcdeef1..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelInitializer -import io.netty.channel.socket.DatagramChannel -import io.netty.handler.timeout.IdleStateHandler - - -open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) : - ChannelInitializer() { - - override fun initChannel(datagramChannel: DatagramChannel) { - val pipeline = datagramChannel.pipeline() - pipeline.addLast( - IdleStateHandler(12, 15, 0) - ).addLast(handler) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt deleted file mode 100644 index 183945a..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt +++ /dev/null @@ -1,101 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import com.casic.br.operationsite.utils.LocaleConstant -import com.pengxh.kt.lite.utils.SaveKeyValues -import io.netty.bootstrap.Bootstrap -import io.netty.buffer.ByteBuf -import io.netty.buffer.Unpooled -import io.netty.channel.ChannelFuture -import io.netty.channel.ChannelOption -import io.netty.channel.nio.NioEventLoopGroup -import io.netty.channel.socket.DatagramPacket -import io.netty.channel.socket.nio.NioDatagramChannel -import io.netty.util.CharsetUtil -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import java.net.InetSocketAddress -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors - - -class UdpClient : UdpChannelInboundHandler(), Runnable { - - private val bootStrap by lazy { Bootstrap() } - private val eventLoopGroup by lazy { NioEventLoopGroup() } - private val udpChannelInitializer by lazy { UdpChannelInitializer(this) } - private var executorService: ExecutorService - - init { - bootStrap.group(eventLoopGroup) - bootStrap.channel(NioDatagramChannel::class.java) - .option(ChannelOption.SO_RCVBUF, 1024) - .option(ChannelOption.SO_SNDBUF, 1024) - bootStrap.handler(udpChannelInitializer) - - executorService = Executors.newSingleThreadExecutor() - executorService.execute(this) - } - - override fun run() { - try { - val channelFuture: ChannelFuture = bootStrap.bind(LocaleConstant.UDP_PORT).sync() - channelFuture.channel().closeFuture().sync() - } catch (e: InterruptedException) { - e.printStackTrace() - } finally { - eventLoopGroup.shutdownGracefully() - } - } - - fun send(value: String) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value, CharsetUtil.UTF_8), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteArray) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteBuf) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun release() { - releasePort() - } - - override fun receivedMessage(data: String) { - - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt new file mode 100644 index 0000000..0acb367 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt @@ -0,0 +1,19 @@ +package com.casic.br.operationsite.utils.netty.tcp + +interface ISocketListener { + companion object { + const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功 + const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接 + const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败 + } + + /** + * 当接收到系统消息 + */ + fun onMessageResponse(data: ByteArray?) + + /** + * 当连接状态发生变化时调用 + */ + fun onServiceStatusConnectChanged(statusCode: Byte) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt new file mode 100644 index 0000000..d381ce0 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt @@ -0,0 +1,34 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.util.Log +import io.netty.channel.ChannelHandlerContext +import io.netty.channel.SimpleChannelInboundHandler + +class SocketChannelHandle(private val listener: ISocketListener?) : + SimpleChannelInboundHandler() { + + private val kTag = "SocketChannelHandle" + + override fun channelActive(ctx: ChannelHandlerContext) { + super.channelActive(ctx) + Log.d(kTag, "channelActive ===> 连接成功") + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS) + } + + override fun channelInactive(ctx: ChannelHandlerContext) { + super.channelInactive(ctx) + Log.e(kTag, "channelInactive: 连接断开") + } + + override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) { + listener?.onMessageResponse(data) + } + + override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) { + super.exceptionCaught(ctx, cause) + Log.d(kTag, "exceptionCaught ===> $cause") + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR) + cause.printStackTrace() + ctx.close() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt new file mode 100644 index 0000000..dffac03 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt @@ -0,0 +1,153 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.os.SystemClock +import android.util.Log +import io.netty.bootstrap.Bootstrap +import io.netty.channel.* +import io.netty.channel.nio.NioEventLoopGroup +import io.netty.channel.socket.SocketChannel +import io.netty.channel.socket.nio.NioSocketChannel +import io.netty.handler.codec.bytes.ByteArrayDecoder +import io.netty.handler.codec.bytes.ByteArrayEncoder +import io.netty.handler.timeout.IdleStateHandler + +class SocketClient { + + private val kTag = "SocketClient" + + private var host: String? = null + private var port = 8000 + private var nioEventLoopGroup: NioEventLoopGroup? = null + private var channel: Channel? = null + private var listener: ISocketListener? = null + + //现在连接的状态 + var connectStatus = false //判断是否已连接 + private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用 + private var isNeedReconnect = true //是否需要重连 + var isConnecting = false //是否正在连接 + private set + private var reconnectIntervalTime: Long = 15000 //重连的时间 + + //重连时间 + fun setReconnectNum(reconnectNum: Int) { + this.reconnectNum = reconnectNum + } + + fun setReconnectIntervalTime(reconnectIntervalTime: Long) { + this.reconnectIntervalTime = reconnectIntervalTime + } + + fun setSocketListener(listener: ISocketListener?) { + this.listener = listener + } + + fun connect(host: String, port: Int) { + this.host = host + this.port = port + Log.d(kTag, "connect ===> 开始连接TCP服务器") + if (isConnecting) { + return + } + //起个线程 + val clientThread: Thread = object : Thread("client-Netty") { + override fun run() { + super.run() + isNeedReconnect = true + reconnectNum = Int.MAX_VALUE + connectServer() + } + } + clientThread.start() + } + + private fun connectServer() { + synchronized(this@SocketClient) { + var channelFuture: ChannelFuture? = null //连接管理对象 + if (!connectStatus) { + isConnecting = true + nioEventLoopGroup = NioEventLoopGroup() //设置的连接group + val bootstrap = Bootstrap() + bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等 + .channel(NioSocketChannel::class.java) + .option(ChannelOption.TCP_NODELAY, true) //无阻塞 + .option(ChannelOption.SO_KEEPALIVE, true) //长连接 + .option( + ChannelOption.RCVBUF_ALLOCATOR, + AdaptiveRecvByteBufAllocator(5000, 5000, 8000) + ) //接收缓冲区 最小值太小时数据接收不全 + .handler(object : ChannelInitializer() { + override fun initChannel(channel: SocketChannel) { + val pipeline = channel.pipeline() + //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调; + //参数2:代表写套接字超时时间,没进行写会触发写超时回调; + //参数3:将在未执行读取或写入时触发超时回调,0代表不处理; + //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接 + pipeline.addLast(IdleStateHandler(60, 10, 0)) + pipeline.addLast(ByteArrayDecoder()) + pipeline.addLast(ByteArrayEncoder()) + pipeline.addLast(SocketChannelHandle(listener)) + } + }) + try { + //连接监听 + channelFuture = bootstrap.connect(host, port) + .addListener(object : ChannelFutureListener { + override fun operationComplete(channelFuture: ChannelFuture) { + if (channelFuture.isSuccess) { + connectStatus = true + channel = channelFuture.channel() + } else { + Log.e(kTag, "operationComplete: 连接失败") + connectStatus = false + } + isConnecting = false + } + }).sync() + // 等待连接关闭 + channelFuture.channel().closeFuture().sync() + } catch (e: Exception) { + e.printStackTrace() + } finally { + connectStatus = false + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识 + if (null != channelFuture) { + if (channelFuture.channel() != null && channelFuture.channel().isOpen) { + channelFuture.channel().close() + } + } + nioEventLoopGroup?.shutdownGracefully() + reconnect() //重新连接 + } + } + } + } + + //断开连接 + fun disconnect() { + Log.d(kTag, "disconnect ===> 断开连接") + isNeedReconnect = false + nioEventLoopGroup?.shutdownGracefully() + } + + //重新连接 + private fun reconnect() { + if (isNeedReconnect && reconnectNum > 0 && !connectStatus) { + reconnectNum-- + SystemClock.sleep(reconnectIntervalTime) + if (isNeedReconnect && reconnectNum > 0 && !connectStatus) { + Log.d(kTag, "reconnect ===> 重新连接") + connectServer() + } + } + } + + fun sendData(bytes: ByteArray) { + channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future -> + if (!future.isSuccess) { + future.channel().close() + nioEventLoopGroup!!.shutdownGracefully() + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketManager.kt new file mode 100644 index 0000000..8c219d5 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketManager.kt @@ -0,0 +1,59 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.util.Log +import com.casic.br.operationsite.view.MethaneActivity +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class SocketManager private constructor() : ISocketListener { + + private val kTag = "SocketManager" + private var nettyClient: SocketClient = SocketClient() + + companion object { + val get by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() } + } + + fun connectNetty(hostname: String, port: Int) { + Thread { + if (!nettyClient.connectStatus) { + nettyClient.setSocketListener(this) + nettyClient.connect(hostname, port) + } else { + nettyClient.disconnect() + } + }.start() + } + + override fun onMessageResponse(data: ByteArray?) { + + } + + override fun onServiceStatusConnectChanged(statusCode: Byte) { + if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) { + if (nettyClient.connectStatus) { + Log.d(kTag, "连接成功") + MethaneActivity.weakReferenceHandler.sendEmptyMessage(2023072101) + } + } else { + if (!nettyClient.connectStatus) { + Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连") + MethaneActivity.weakReferenceHandler.sendEmptyMessage(2023072102) + } + } + } + + fun send(data: ByteArray) { + CoroutineScope(Dispatchers.Main).launch { + withContext(Dispatchers.IO) { + nettyClient.sendData(data) + } + } + } + + fun close() { + nettyClient.disconnect() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt index 1db4e7c..f50c0f7 100644 --- a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt @@ -34,4 +34,5 @@ const val WIFI_PASSWORD = "zhsz20311hw" const val UDP_HOST = "udpServer" const val UDP_PORT = 9000 + const val TCP_PORT = 9000 } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt deleted file mode 100644 index a7f9d27..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelHandlerContext -import io.netty.channel.SimpleChannelInboundHandler -import io.netty.channel.socket.DatagramPacket -import io.netty.util.CharsetUtil - - -abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() { - - private var handlerContext: ChannelHandlerContext? = null - - override fun channelActive(ctx: ChannelHandlerContext?) { - super.channelActive(ctx) - handlerContext = ctx - } - - override fun channelInactive(ctx: ChannelHandlerContext?) { - super.channelInactive(ctx) - handlerContext?.close() - } - - fun sendDatagramPacket(obj: Any) { - handlerContext?.writeAndFlush(obj) - } - - fun releasePort() { - handlerContext?.close() - } - - override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) { - receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8)) - } - - abstract fun receivedMessage(data: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt deleted file mode 100644 index bcdeef1..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelInitializer -import io.netty.channel.socket.DatagramChannel -import io.netty.handler.timeout.IdleStateHandler - - -open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) : - ChannelInitializer() { - - override fun initChannel(datagramChannel: DatagramChannel) { - val pipeline = datagramChannel.pipeline() - pipeline.addLast( - IdleStateHandler(12, 15, 0) - ).addLast(handler) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt deleted file mode 100644 index 183945a..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt +++ /dev/null @@ -1,101 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import com.casic.br.operationsite.utils.LocaleConstant -import com.pengxh.kt.lite.utils.SaveKeyValues -import io.netty.bootstrap.Bootstrap -import io.netty.buffer.ByteBuf -import io.netty.buffer.Unpooled -import io.netty.channel.ChannelFuture -import io.netty.channel.ChannelOption -import io.netty.channel.nio.NioEventLoopGroup -import io.netty.channel.socket.DatagramPacket -import io.netty.channel.socket.nio.NioDatagramChannel -import io.netty.util.CharsetUtil -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import java.net.InetSocketAddress -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors - - -class UdpClient : UdpChannelInboundHandler(), Runnable { - - private val bootStrap by lazy { Bootstrap() } - private val eventLoopGroup by lazy { NioEventLoopGroup() } - private val udpChannelInitializer by lazy { UdpChannelInitializer(this) } - private var executorService: ExecutorService - - init { - bootStrap.group(eventLoopGroup) - bootStrap.channel(NioDatagramChannel::class.java) - .option(ChannelOption.SO_RCVBUF, 1024) - .option(ChannelOption.SO_SNDBUF, 1024) - bootStrap.handler(udpChannelInitializer) - - executorService = Executors.newSingleThreadExecutor() - executorService.execute(this) - } - - override fun run() { - try { - val channelFuture: ChannelFuture = bootStrap.bind(LocaleConstant.UDP_PORT).sync() - channelFuture.channel().closeFuture().sync() - } catch (e: InterruptedException) { - e.printStackTrace() - } finally { - eventLoopGroup.shutdownGracefully() - } - } - - fun send(value: String) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value, CharsetUtil.UTF_8), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteArray) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteBuf) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun release() { - releasePort() - } - - override fun receivedMessage(data: String) { - - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt new file mode 100644 index 0000000..0acb367 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt @@ -0,0 +1,19 @@ +package com.casic.br.operationsite.utils.netty.tcp + +interface ISocketListener { + companion object { + const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功 + const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接 + const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败 + } + + /** + * 当接收到系统消息 + */ + fun onMessageResponse(data: ByteArray?) + + /** + * 当连接状态发生变化时调用 + */ + fun onServiceStatusConnectChanged(statusCode: Byte) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt new file mode 100644 index 0000000..d381ce0 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt @@ -0,0 +1,34 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.util.Log +import io.netty.channel.ChannelHandlerContext +import io.netty.channel.SimpleChannelInboundHandler + +class SocketChannelHandle(private val listener: ISocketListener?) : + SimpleChannelInboundHandler() { + + private val kTag = "SocketChannelHandle" + + override fun channelActive(ctx: ChannelHandlerContext) { + super.channelActive(ctx) + Log.d(kTag, "channelActive ===> 连接成功") + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS) + } + + override fun channelInactive(ctx: ChannelHandlerContext) { + super.channelInactive(ctx) + Log.e(kTag, "channelInactive: 连接断开") + } + + override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) { + listener?.onMessageResponse(data) + } + + override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) { + super.exceptionCaught(ctx, cause) + Log.d(kTag, "exceptionCaught ===> $cause") + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR) + cause.printStackTrace() + ctx.close() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt new file mode 100644 index 0000000..dffac03 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt @@ -0,0 +1,153 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.os.SystemClock +import android.util.Log +import io.netty.bootstrap.Bootstrap +import io.netty.channel.* +import io.netty.channel.nio.NioEventLoopGroup +import io.netty.channel.socket.SocketChannel +import io.netty.channel.socket.nio.NioSocketChannel +import io.netty.handler.codec.bytes.ByteArrayDecoder +import io.netty.handler.codec.bytes.ByteArrayEncoder +import io.netty.handler.timeout.IdleStateHandler + +class SocketClient { + + private val kTag = "SocketClient" + + private var host: String? = null + private var port = 8000 + private var nioEventLoopGroup: NioEventLoopGroup? = null + private var channel: Channel? = null + private var listener: ISocketListener? = null + + //现在连接的状态 + var connectStatus = false //判断是否已连接 + private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用 + private var isNeedReconnect = true //是否需要重连 + var isConnecting = false //是否正在连接 + private set + private var reconnectIntervalTime: Long = 15000 //重连的时间 + + //重连时间 + fun setReconnectNum(reconnectNum: Int) { + this.reconnectNum = reconnectNum + } + + fun setReconnectIntervalTime(reconnectIntervalTime: Long) { + this.reconnectIntervalTime = reconnectIntervalTime + } + + fun setSocketListener(listener: ISocketListener?) { + this.listener = listener + } + + fun connect(host: String, port: Int) { + this.host = host + this.port = port + Log.d(kTag, "connect ===> 开始连接TCP服务器") + if (isConnecting) { + return + } + //起个线程 + val clientThread: Thread = object : Thread("client-Netty") { + override fun run() { + super.run() + isNeedReconnect = true + reconnectNum = Int.MAX_VALUE + connectServer() + } + } + clientThread.start() + } + + private fun connectServer() { + synchronized(this@SocketClient) { + var channelFuture: ChannelFuture? = null //连接管理对象 + if (!connectStatus) { + isConnecting = true + nioEventLoopGroup = NioEventLoopGroup() //设置的连接group + val bootstrap = Bootstrap() + bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等 + .channel(NioSocketChannel::class.java) + .option(ChannelOption.TCP_NODELAY, true) //无阻塞 + .option(ChannelOption.SO_KEEPALIVE, true) //长连接 + .option( + ChannelOption.RCVBUF_ALLOCATOR, + AdaptiveRecvByteBufAllocator(5000, 5000, 8000) + ) //接收缓冲区 最小值太小时数据接收不全 + .handler(object : ChannelInitializer() { + override fun initChannel(channel: SocketChannel) { + val pipeline = channel.pipeline() + //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调; + //参数2:代表写套接字超时时间,没进行写会触发写超时回调; + //参数3:将在未执行读取或写入时触发超时回调,0代表不处理; + //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接 + pipeline.addLast(IdleStateHandler(60, 10, 0)) + pipeline.addLast(ByteArrayDecoder()) + pipeline.addLast(ByteArrayEncoder()) + pipeline.addLast(SocketChannelHandle(listener)) + } + }) + try { + //连接监听 + channelFuture = bootstrap.connect(host, port) + .addListener(object : ChannelFutureListener { + override fun operationComplete(channelFuture: ChannelFuture) { + if (channelFuture.isSuccess) { + connectStatus = true + channel = channelFuture.channel() + } else { + Log.e(kTag, "operationComplete: 连接失败") + connectStatus = false + } + isConnecting = false + } + }).sync() + // 等待连接关闭 + channelFuture.channel().closeFuture().sync() + } catch (e: Exception) { + e.printStackTrace() + } finally { + connectStatus = false + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识 + if (null != channelFuture) { + if (channelFuture.channel() != null && channelFuture.channel().isOpen) { + channelFuture.channel().close() + } + } + nioEventLoopGroup?.shutdownGracefully() + reconnect() //重新连接 + } + } + } + } + + //断开连接 + fun disconnect() { + Log.d(kTag, "disconnect ===> 断开连接") + isNeedReconnect = false + nioEventLoopGroup?.shutdownGracefully() + } + + //重新连接 + private fun reconnect() { + if (isNeedReconnect && reconnectNum > 0 && !connectStatus) { + reconnectNum-- + SystemClock.sleep(reconnectIntervalTime) + if (isNeedReconnect && reconnectNum > 0 && !connectStatus) { + Log.d(kTag, "reconnect ===> 重新连接") + connectServer() + } + } + } + + fun sendData(bytes: ByteArray) { + channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future -> + if (!future.isSuccess) { + future.channel().close() + nioEventLoopGroup!!.shutdownGracefully() + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketManager.kt new file mode 100644 index 0000000..8c219d5 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketManager.kt @@ -0,0 +1,59 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.util.Log +import com.casic.br.operationsite.view.MethaneActivity +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class SocketManager private constructor() : ISocketListener { + + private val kTag = "SocketManager" + private var nettyClient: SocketClient = SocketClient() + + companion object { + val get by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() } + } + + fun connectNetty(hostname: String, port: Int) { + Thread { + if (!nettyClient.connectStatus) { + nettyClient.setSocketListener(this) + nettyClient.connect(hostname, port) + } else { + nettyClient.disconnect() + } + }.start() + } + + override fun onMessageResponse(data: ByteArray?) { + + } + + override fun onServiceStatusConnectChanged(statusCode: Byte) { + if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) { + if (nettyClient.connectStatus) { + Log.d(kTag, "连接成功") + MethaneActivity.weakReferenceHandler.sendEmptyMessage(2023072101) + } + } else { + if (!nettyClient.connectStatus) { + Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连") + MethaneActivity.weakReferenceHandler.sendEmptyMessage(2023072102) + } + } + } + + fun send(data: ByteArray) { + CoroutineScope(Dispatchers.Main).launch { + withContext(Dispatchers.IO) { + nettyClient.sendData(data) + } + } + } + + fun close() { + nettyClient.disconnect() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInboundHandler.kt new file mode 100644 index 0000000..02284cc --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInboundHandler.kt @@ -0,0 +1,36 @@ +package com.casic.br.operationsite.utils.netty.udp + +import io.netty.channel.ChannelHandlerContext +import io.netty.channel.SimpleChannelInboundHandler +import io.netty.channel.socket.DatagramPacket +import io.netty.util.CharsetUtil + + +abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() { + + private var handlerContext: ChannelHandlerContext? = null + + override fun channelActive(ctx: ChannelHandlerContext?) { + super.channelActive(ctx) + handlerContext = ctx + } + + override fun channelInactive(ctx: ChannelHandlerContext?) { + super.channelInactive(ctx) + handlerContext?.close() + } + + fun sendDatagramPacket(obj: Any) { + handlerContext?.writeAndFlush(obj) + } + + fun releasePort() { + handlerContext?.close() + } + + override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) { + receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8)) + } + + abstract fun receivedMessage(data: String) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt index 1db4e7c..f50c0f7 100644 --- a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt @@ -34,4 +34,5 @@ const val WIFI_PASSWORD = "zhsz20311hw" const val UDP_HOST = "udpServer" const val UDP_PORT = 9000 + const val TCP_PORT = 9000 } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt deleted file mode 100644 index a7f9d27..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelHandlerContext -import io.netty.channel.SimpleChannelInboundHandler -import io.netty.channel.socket.DatagramPacket -import io.netty.util.CharsetUtil - - -abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() { - - private var handlerContext: ChannelHandlerContext? = null - - override fun channelActive(ctx: ChannelHandlerContext?) { - super.channelActive(ctx) - handlerContext = ctx - } - - override fun channelInactive(ctx: ChannelHandlerContext?) { - super.channelInactive(ctx) - handlerContext?.close() - } - - fun sendDatagramPacket(obj: Any) { - handlerContext?.writeAndFlush(obj) - } - - fun releasePort() { - handlerContext?.close() - } - - override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) { - receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8)) - } - - abstract fun receivedMessage(data: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt deleted file mode 100644 index bcdeef1..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelInitializer -import io.netty.channel.socket.DatagramChannel -import io.netty.handler.timeout.IdleStateHandler - - -open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) : - ChannelInitializer() { - - override fun initChannel(datagramChannel: DatagramChannel) { - val pipeline = datagramChannel.pipeline() - pipeline.addLast( - IdleStateHandler(12, 15, 0) - ).addLast(handler) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt deleted file mode 100644 index 183945a..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt +++ /dev/null @@ -1,101 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import com.casic.br.operationsite.utils.LocaleConstant -import com.pengxh.kt.lite.utils.SaveKeyValues -import io.netty.bootstrap.Bootstrap -import io.netty.buffer.ByteBuf -import io.netty.buffer.Unpooled -import io.netty.channel.ChannelFuture -import io.netty.channel.ChannelOption -import io.netty.channel.nio.NioEventLoopGroup -import io.netty.channel.socket.DatagramPacket -import io.netty.channel.socket.nio.NioDatagramChannel -import io.netty.util.CharsetUtil -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import java.net.InetSocketAddress -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors - - -class UdpClient : UdpChannelInboundHandler(), Runnable { - - private val bootStrap by lazy { Bootstrap() } - private val eventLoopGroup by lazy { NioEventLoopGroup() } - private val udpChannelInitializer by lazy { UdpChannelInitializer(this) } - private var executorService: ExecutorService - - init { - bootStrap.group(eventLoopGroup) - bootStrap.channel(NioDatagramChannel::class.java) - .option(ChannelOption.SO_RCVBUF, 1024) - .option(ChannelOption.SO_SNDBUF, 1024) - bootStrap.handler(udpChannelInitializer) - - executorService = Executors.newSingleThreadExecutor() - executorService.execute(this) - } - - override fun run() { - try { - val channelFuture: ChannelFuture = bootStrap.bind(LocaleConstant.UDP_PORT).sync() - channelFuture.channel().closeFuture().sync() - } catch (e: InterruptedException) { - e.printStackTrace() - } finally { - eventLoopGroup.shutdownGracefully() - } - } - - fun send(value: String) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value, CharsetUtil.UTF_8), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteArray) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteBuf) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun release() { - releasePort() - } - - override fun receivedMessage(data: String) { - - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt new file mode 100644 index 0000000..0acb367 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt @@ -0,0 +1,19 @@ +package com.casic.br.operationsite.utils.netty.tcp + +interface ISocketListener { + companion object { + const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功 + const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接 + const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败 + } + + /** + * 当接收到系统消息 + */ + fun onMessageResponse(data: ByteArray?) + + /** + * 当连接状态发生变化时调用 + */ + fun onServiceStatusConnectChanged(statusCode: Byte) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt new file mode 100644 index 0000000..d381ce0 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt @@ -0,0 +1,34 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.util.Log +import io.netty.channel.ChannelHandlerContext +import io.netty.channel.SimpleChannelInboundHandler + +class SocketChannelHandle(private val listener: ISocketListener?) : + SimpleChannelInboundHandler() { + + private val kTag = "SocketChannelHandle" + + override fun channelActive(ctx: ChannelHandlerContext) { + super.channelActive(ctx) + Log.d(kTag, "channelActive ===> 连接成功") + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS) + } + + override fun channelInactive(ctx: ChannelHandlerContext) { + super.channelInactive(ctx) + Log.e(kTag, "channelInactive: 连接断开") + } + + override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) { + listener?.onMessageResponse(data) + } + + override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) { + super.exceptionCaught(ctx, cause) + Log.d(kTag, "exceptionCaught ===> $cause") + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR) + cause.printStackTrace() + ctx.close() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt new file mode 100644 index 0000000..dffac03 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt @@ -0,0 +1,153 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.os.SystemClock +import android.util.Log +import io.netty.bootstrap.Bootstrap +import io.netty.channel.* +import io.netty.channel.nio.NioEventLoopGroup +import io.netty.channel.socket.SocketChannel +import io.netty.channel.socket.nio.NioSocketChannel +import io.netty.handler.codec.bytes.ByteArrayDecoder +import io.netty.handler.codec.bytes.ByteArrayEncoder +import io.netty.handler.timeout.IdleStateHandler + +class SocketClient { + + private val kTag = "SocketClient" + + private var host: String? = null + private var port = 8000 + private var nioEventLoopGroup: NioEventLoopGroup? = null + private var channel: Channel? = null + private var listener: ISocketListener? = null + + //现在连接的状态 + var connectStatus = false //判断是否已连接 + private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用 + private var isNeedReconnect = true //是否需要重连 + var isConnecting = false //是否正在连接 + private set + private var reconnectIntervalTime: Long = 15000 //重连的时间 + + //重连时间 + fun setReconnectNum(reconnectNum: Int) { + this.reconnectNum = reconnectNum + } + + fun setReconnectIntervalTime(reconnectIntervalTime: Long) { + this.reconnectIntervalTime = reconnectIntervalTime + } + + fun setSocketListener(listener: ISocketListener?) { + this.listener = listener + } + + fun connect(host: String, port: Int) { + this.host = host + this.port = port + Log.d(kTag, "connect ===> 开始连接TCP服务器") + if (isConnecting) { + return + } + //起个线程 + val clientThread: Thread = object : Thread("client-Netty") { + override fun run() { + super.run() + isNeedReconnect = true + reconnectNum = Int.MAX_VALUE + connectServer() + } + } + clientThread.start() + } + + private fun connectServer() { + synchronized(this@SocketClient) { + var channelFuture: ChannelFuture? = null //连接管理对象 + if (!connectStatus) { + isConnecting = true + nioEventLoopGroup = NioEventLoopGroup() //设置的连接group + val bootstrap = Bootstrap() + bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等 + .channel(NioSocketChannel::class.java) + .option(ChannelOption.TCP_NODELAY, true) //无阻塞 + .option(ChannelOption.SO_KEEPALIVE, true) //长连接 + .option( + ChannelOption.RCVBUF_ALLOCATOR, + AdaptiveRecvByteBufAllocator(5000, 5000, 8000) + ) //接收缓冲区 最小值太小时数据接收不全 + .handler(object : ChannelInitializer() { + override fun initChannel(channel: SocketChannel) { + val pipeline = channel.pipeline() + //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调; + //参数2:代表写套接字超时时间,没进行写会触发写超时回调; + //参数3:将在未执行读取或写入时触发超时回调,0代表不处理; + //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接 + pipeline.addLast(IdleStateHandler(60, 10, 0)) + pipeline.addLast(ByteArrayDecoder()) + pipeline.addLast(ByteArrayEncoder()) + pipeline.addLast(SocketChannelHandle(listener)) + } + }) + try { + //连接监听 + channelFuture = bootstrap.connect(host, port) + .addListener(object : ChannelFutureListener { + override fun operationComplete(channelFuture: ChannelFuture) { + if (channelFuture.isSuccess) { + connectStatus = true + channel = channelFuture.channel() + } else { + Log.e(kTag, "operationComplete: 连接失败") + connectStatus = false + } + isConnecting = false + } + }).sync() + // 等待连接关闭 + channelFuture.channel().closeFuture().sync() + } catch (e: Exception) { + e.printStackTrace() + } finally { + connectStatus = false + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识 + if (null != channelFuture) { + if (channelFuture.channel() != null && channelFuture.channel().isOpen) { + channelFuture.channel().close() + } + } + nioEventLoopGroup?.shutdownGracefully() + reconnect() //重新连接 + } + } + } + } + + //断开连接 + fun disconnect() { + Log.d(kTag, "disconnect ===> 断开连接") + isNeedReconnect = false + nioEventLoopGroup?.shutdownGracefully() + } + + //重新连接 + private fun reconnect() { + if (isNeedReconnect && reconnectNum > 0 && !connectStatus) { + reconnectNum-- + SystemClock.sleep(reconnectIntervalTime) + if (isNeedReconnect && reconnectNum > 0 && !connectStatus) { + Log.d(kTag, "reconnect ===> 重新连接") + connectServer() + } + } + } + + fun sendData(bytes: ByteArray) { + channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future -> + if (!future.isSuccess) { + future.channel().close() + nioEventLoopGroup!!.shutdownGracefully() + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketManager.kt new file mode 100644 index 0000000..8c219d5 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketManager.kt @@ -0,0 +1,59 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.util.Log +import com.casic.br.operationsite.view.MethaneActivity +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class SocketManager private constructor() : ISocketListener { + + private val kTag = "SocketManager" + private var nettyClient: SocketClient = SocketClient() + + companion object { + val get by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() } + } + + fun connectNetty(hostname: String, port: Int) { + Thread { + if (!nettyClient.connectStatus) { + nettyClient.setSocketListener(this) + nettyClient.connect(hostname, port) + } else { + nettyClient.disconnect() + } + }.start() + } + + override fun onMessageResponse(data: ByteArray?) { + + } + + override fun onServiceStatusConnectChanged(statusCode: Byte) { + if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) { + if (nettyClient.connectStatus) { + Log.d(kTag, "连接成功") + MethaneActivity.weakReferenceHandler.sendEmptyMessage(2023072101) + } + } else { + if (!nettyClient.connectStatus) { + Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连") + MethaneActivity.weakReferenceHandler.sendEmptyMessage(2023072102) + } + } + } + + fun send(data: ByteArray) { + CoroutineScope(Dispatchers.Main).launch { + withContext(Dispatchers.IO) { + nettyClient.sendData(data) + } + } + } + + fun close() { + nettyClient.disconnect() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInboundHandler.kt new file mode 100644 index 0000000..02284cc --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInboundHandler.kt @@ -0,0 +1,36 @@ +package com.casic.br.operationsite.utils.netty.udp + +import io.netty.channel.ChannelHandlerContext +import io.netty.channel.SimpleChannelInboundHandler +import io.netty.channel.socket.DatagramPacket +import io.netty.util.CharsetUtil + + +abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() { + + private var handlerContext: ChannelHandlerContext? = null + + override fun channelActive(ctx: ChannelHandlerContext?) { + super.channelActive(ctx) + handlerContext = ctx + } + + override fun channelInactive(ctx: ChannelHandlerContext?) { + super.channelInactive(ctx) + handlerContext?.close() + } + + fun sendDatagramPacket(obj: Any) { + handlerContext?.writeAndFlush(obj) + } + + fun releasePort() { + handlerContext?.close() + } + + override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) { + receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8)) + } + + abstract fun receivedMessage(data: String) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInitializer.kt new file mode 100644 index 0000000..5545b56 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInitializer.kt @@ -0,0 +1,17 @@ +package com.casic.br.operationsite.utils.netty.udp + +import io.netty.channel.ChannelInitializer +import io.netty.channel.socket.DatagramChannel +import io.netty.handler.timeout.IdleStateHandler + + +open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) : + ChannelInitializer() { + + override fun initChannel(datagramChannel: DatagramChannel) { + val pipeline = datagramChannel.pipeline() + pipeline.addLast( + IdleStateHandler(12, 15, 0) + ).addLast(handler) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt index 1db4e7c..f50c0f7 100644 --- a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt @@ -34,4 +34,5 @@ const val WIFI_PASSWORD = "zhsz20311hw" const val UDP_HOST = "udpServer" const val UDP_PORT = 9000 + const val TCP_PORT = 9000 } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt deleted file mode 100644 index a7f9d27..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelHandlerContext -import io.netty.channel.SimpleChannelInboundHandler -import io.netty.channel.socket.DatagramPacket -import io.netty.util.CharsetUtil - - -abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() { - - private var handlerContext: ChannelHandlerContext? = null - - override fun channelActive(ctx: ChannelHandlerContext?) { - super.channelActive(ctx) - handlerContext = ctx - } - - override fun channelInactive(ctx: ChannelHandlerContext?) { - super.channelInactive(ctx) - handlerContext?.close() - } - - fun sendDatagramPacket(obj: Any) { - handlerContext?.writeAndFlush(obj) - } - - fun releasePort() { - handlerContext?.close() - } - - override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) { - receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8)) - } - - abstract fun receivedMessage(data: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt deleted file mode 100644 index bcdeef1..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelInitializer -import io.netty.channel.socket.DatagramChannel -import io.netty.handler.timeout.IdleStateHandler - - -open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) : - ChannelInitializer() { - - override fun initChannel(datagramChannel: DatagramChannel) { - val pipeline = datagramChannel.pipeline() - pipeline.addLast( - IdleStateHandler(12, 15, 0) - ).addLast(handler) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt deleted file mode 100644 index 183945a..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt +++ /dev/null @@ -1,101 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import com.casic.br.operationsite.utils.LocaleConstant -import com.pengxh.kt.lite.utils.SaveKeyValues -import io.netty.bootstrap.Bootstrap -import io.netty.buffer.ByteBuf -import io.netty.buffer.Unpooled -import io.netty.channel.ChannelFuture -import io.netty.channel.ChannelOption -import io.netty.channel.nio.NioEventLoopGroup -import io.netty.channel.socket.DatagramPacket -import io.netty.channel.socket.nio.NioDatagramChannel -import io.netty.util.CharsetUtil -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import java.net.InetSocketAddress -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors - - -class UdpClient : UdpChannelInboundHandler(), Runnable { - - private val bootStrap by lazy { Bootstrap() } - private val eventLoopGroup by lazy { NioEventLoopGroup() } - private val udpChannelInitializer by lazy { UdpChannelInitializer(this) } - private var executorService: ExecutorService - - init { - bootStrap.group(eventLoopGroup) - bootStrap.channel(NioDatagramChannel::class.java) - .option(ChannelOption.SO_RCVBUF, 1024) - .option(ChannelOption.SO_SNDBUF, 1024) - bootStrap.handler(udpChannelInitializer) - - executorService = Executors.newSingleThreadExecutor() - executorService.execute(this) - } - - override fun run() { - try { - val channelFuture: ChannelFuture = bootStrap.bind(LocaleConstant.UDP_PORT).sync() - channelFuture.channel().closeFuture().sync() - } catch (e: InterruptedException) { - e.printStackTrace() - } finally { - eventLoopGroup.shutdownGracefully() - } - } - - fun send(value: String) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value, CharsetUtil.UTF_8), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteArray) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteBuf) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun release() { - releasePort() - } - - override fun receivedMessage(data: String) { - - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt new file mode 100644 index 0000000..0acb367 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt @@ -0,0 +1,19 @@ +package com.casic.br.operationsite.utils.netty.tcp + +interface ISocketListener { + companion object { + const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功 + const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接 + const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败 + } + + /** + * 当接收到系统消息 + */ + fun onMessageResponse(data: ByteArray?) + + /** + * 当连接状态发生变化时调用 + */ + fun onServiceStatusConnectChanged(statusCode: Byte) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt new file mode 100644 index 0000000..d381ce0 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt @@ -0,0 +1,34 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.util.Log +import io.netty.channel.ChannelHandlerContext +import io.netty.channel.SimpleChannelInboundHandler + +class SocketChannelHandle(private val listener: ISocketListener?) : + SimpleChannelInboundHandler() { + + private val kTag = "SocketChannelHandle" + + override fun channelActive(ctx: ChannelHandlerContext) { + super.channelActive(ctx) + Log.d(kTag, "channelActive ===> 连接成功") + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS) + } + + override fun channelInactive(ctx: ChannelHandlerContext) { + super.channelInactive(ctx) + Log.e(kTag, "channelInactive: 连接断开") + } + + override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) { + listener?.onMessageResponse(data) + } + + override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) { + super.exceptionCaught(ctx, cause) + Log.d(kTag, "exceptionCaught ===> $cause") + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR) + cause.printStackTrace() + ctx.close() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt new file mode 100644 index 0000000..dffac03 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt @@ -0,0 +1,153 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.os.SystemClock +import android.util.Log +import io.netty.bootstrap.Bootstrap +import io.netty.channel.* +import io.netty.channel.nio.NioEventLoopGroup +import io.netty.channel.socket.SocketChannel +import io.netty.channel.socket.nio.NioSocketChannel +import io.netty.handler.codec.bytes.ByteArrayDecoder +import io.netty.handler.codec.bytes.ByteArrayEncoder +import io.netty.handler.timeout.IdleStateHandler + +class SocketClient { + + private val kTag = "SocketClient" + + private var host: String? = null + private var port = 8000 + private var nioEventLoopGroup: NioEventLoopGroup? = null + private var channel: Channel? = null + private var listener: ISocketListener? = null + + //现在连接的状态 + var connectStatus = false //判断是否已连接 + private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用 + private var isNeedReconnect = true //是否需要重连 + var isConnecting = false //是否正在连接 + private set + private var reconnectIntervalTime: Long = 15000 //重连的时间 + + //重连时间 + fun setReconnectNum(reconnectNum: Int) { + this.reconnectNum = reconnectNum + } + + fun setReconnectIntervalTime(reconnectIntervalTime: Long) { + this.reconnectIntervalTime = reconnectIntervalTime + } + + fun setSocketListener(listener: ISocketListener?) { + this.listener = listener + } + + fun connect(host: String, port: Int) { + this.host = host + this.port = port + Log.d(kTag, "connect ===> 开始连接TCP服务器") + if (isConnecting) { + return + } + //起个线程 + val clientThread: Thread = object : Thread("client-Netty") { + override fun run() { + super.run() + isNeedReconnect = true + reconnectNum = Int.MAX_VALUE + connectServer() + } + } + clientThread.start() + } + + private fun connectServer() { + synchronized(this@SocketClient) { + var channelFuture: ChannelFuture? = null //连接管理对象 + if (!connectStatus) { + isConnecting = true + nioEventLoopGroup = NioEventLoopGroup() //设置的连接group + val bootstrap = Bootstrap() + bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等 + .channel(NioSocketChannel::class.java) + .option(ChannelOption.TCP_NODELAY, true) //无阻塞 + .option(ChannelOption.SO_KEEPALIVE, true) //长连接 + .option( + ChannelOption.RCVBUF_ALLOCATOR, + AdaptiveRecvByteBufAllocator(5000, 5000, 8000) + ) //接收缓冲区 最小值太小时数据接收不全 + .handler(object : ChannelInitializer() { + override fun initChannel(channel: SocketChannel) { + val pipeline = channel.pipeline() + //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调; + //参数2:代表写套接字超时时间,没进行写会触发写超时回调; + //参数3:将在未执行读取或写入时触发超时回调,0代表不处理; + //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接 + pipeline.addLast(IdleStateHandler(60, 10, 0)) + pipeline.addLast(ByteArrayDecoder()) + pipeline.addLast(ByteArrayEncoder()) + pipeline.addLast(SocketChannelHandle(listener)) + } + }) + try { + //连接监听 + channelFuture = bootstrap.connect(host, port) + .addListener(object : ChannelFutureListener { + override fun operationComplete(channelFuture: ChannelFuture) { + if (channelFuture.isSuccess) { + connectStatus = true + channel = channelFuture.channel() + } else { + Log.e(kTag, "operationComplete: 连接失败") + connectStatus = false + } + isConnecting = false + } + }).sync() + // 等待连接关闭 + channelFuture.channel().closeFuture().sync() + } catch (e: Exception) { + e.printStackTrace() + } finally { + connectStatus = false + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识 + if (null != channelFuture) { + if (channelFuture.channel() != null && channelFuture.channel().isOpen) { + channelFuture.channel().close() + } + } + nioEventLoopGroup?.shutdownGracefully() + reconnect() //重新连接 + } + } + } + } + + //断开连接 + fun disconnect() { + Log.d(kTag, "disconnect ===> 断开连接") + isNeedReconnect = false + nioEventLoopGroup?.shutdownGracefully() + } + + //重新连接 + private fun reconnect() { + if (isNeedReconnect && reconnectNum > 0 && !connectStatus) { + reconnectNum-- + SystemClock.sleep(reconnectIntervalTime) + if (isNeedReconnect && reconnectNum > 0 && !connectStatus) { + Log.d(kTag, "reconnect ===> 重新连接") + connectServer() + } + } + } + + fun sendData(bytes: ByteArray) { + channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future -> + if (!future.isSuccess) { + future.channel().close() + nioEventLoopGroup!!.shutdownGracefully() + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketManager.kt new file mode 100644 index 0000000..8c219d5 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketManager.kt @@ -0,0 +1,59 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.util.Log +import com.casic.br.operationsite.view.MethaneActivity +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class SocketManager private constructor() : ISocketListener { + + private val kTag = "SocketManager" + private var nettyClient: SocketClient = SocketClient() + + companion object { + val get by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() } + } + + fun connectNetty(hostname: String, port: Int) { + Thread { + if (!nettyClient.connectStatus) { + nettyClient.setSocketListener(this) + nettyClient.connect(hostname, port) + } else { + nettyClient.disconnect() + } + }.start() + } + + override fun onMessageResponse(data: ByteArray?) { + + } + + override fun onServiceStatusConnectChanged(statusCode: Byte) { + if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) { + if (nettyClient.connectStatus) { + Log.d(kTag, "连接成功") + MethaneActivity.weakReferenceHandler.sendEmptyMessage(2023072101) + } + } else { + if (!nettyClient.connectStatus) { + Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连") + MethaneActivity.weakReferenceHandler.sendEmptyMessage(2023072102) + } + } + } + + fun send(data: ByteArray) { + CoroutineScope(Dispatchers.Main).launch { + withContext(Dispatchers.IO) { + nettyClient.sendData(data) + } + } + } + + fun close() { + nettyClient.disconnect() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInboundHandler.kt new file mode 100644 index 0000000..02284cc --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInboundHandler.kt @@ -0,0 +1,36 @@ +package com.casic.br.operationsite.utils.netty.udp + +import io.netty.channel.ChannelHandlerContext +import io.netty.channel.SimpleChannelInboundHandler +import io.netty.channel.socket.DatagramPacket +import io.netty.util.CharsetUtil + + +abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() { + + private var handlerContext: ChannelHandlerContext? = null + + override fun channelActive(ctx: ChannelHandlerContext?) { + super.channelActive(ctx) + handlerContext = ctx + } + + override fun channelInactive(ctx: ChannelHandlerContext?) { + super.channelInactive(ctx) + handlerContext?.close() + } + + fun sendDatagramPacket(obj: Any) { + handlerContext?.writeAndFlush(obj) + } + + fun releasePort() { + handlerContext?.close() + } + + override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) { + receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8)) + } + + abstract fun receivedMessage(data: String) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInitializer.kt new file mode 100644 index 0000000..5545b56 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInitializer.kt @@ -0,0 +1,17 @@ +package com.casic.br.operationsite.utils.netty.udp + +import io.netty.channel.ChannelInitializer +import io.netty.channel.socket.DatagramChannel +import io.netty.handler.timeout.IdleStateHandler + + +open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) : + ChannelInitializer() { + + override fun initChannel(datagramChannel: DatagramChannel) { + val pipeline = datagramChannel.pipeline() + pipeline.addLast( + IdleStateHandler(12, 15, 0) + ).addLast(handler) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpClient.kt new file mode 100644 index 0000000..05a1375 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpClient.kt @@ -0,0 +1,71 @@ +package com.casic.br.operationsite.utils.netty.udp + +import com.casic.br.operationsite.utils.LocaleConstant +import com.pengxh.kt.lite.utils.SaveKeyValues +import io.netty.bootstrap.Bootstrap +import io.netty.buffer.Unpooled +import io.netty.channel.ChannelFuture +import io.netty.channel.ChannelOption +import io.netty.channel.nio.NioEventLoopGroup +import io.netty.channel.socket.DatagramPacket +import io.netty.channel.socket.nio.NioDatagramChannel +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.net.InetSocketAddress +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors + + +class UdpClient : UdpChannelInboundHandler(), Runnable { + + private val bootStrap by lazy { Bootstrap() } + private val eventLoopGroup by lazy { NioEventLoopGroup() } + private val udpChannelInitializer by lazy { UdpChannelInitializer(this) } + private var executorService: ExecutorService + + init { + bootStrap.group(eventLoopGroup) + bootStrap.channel(NioDatagramChannel::class.java) + .option(ChannelOption.SO_RCVBUF, 1024) + .option(ChannelOption.SO_SNDBUF, 1024) + bootStrap.handler(udpChannelInitializer) + + executorService = Executors.newSingleThreadExecutor() + executorService.execute(this) + } + + override fun run() { + try { + val channelFuture: ChannelFuture = bootStrap.bind(LocaleConstant.UDP_PORT).sync() + channelFuture.channel().closeFuture().sync() + } catch (e: InterruptedException) { + e.printStackTrace() + } finally { + eventLoopGroup.shutdownGracefully() + } + } + + fun send(value: ByteArray) { + CoroutineScope(Dispatchers.Main).launch { + withContext(Dispatchers.IO) { + val host = + SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() + val datagramPacket = DatagramPacket( + Unpooled.copiedBuffer(value), + InetSocketAddress(host, LocaleConstant.UDP_PORT) + ) + sendDatagramPacket(datagramPacket) + } + } + } + + fun release() { + releasePort() + } + + override fun receivedMessage(data: String) { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt index 1db4e7c..f50c0f7 100644 --- a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt @@ -34,4 +34,5 @@ const val WIFI_PASSWORD = "zhsz20311hw" const val UDP_HOST = "udpServer" const val UDP_PORT = 9000 + const val TCP_PORT = 9000 } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt deleted file mode 100644 index a7f9d27..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelHandlerContext -import io.netty.channel.SimpleChannelInboundHandler -import io.netty.channel.socket.DatagramPacket -import io.netty.util.CharsetUtil - - -abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() { - - private var handlerContext: ChannelHandlerContext? = null - - override fun channelActive(ctx: ChannelHandlerContext?) { - super.channelActive(ctx) - handlerContext = ctx - } - - override fun channelInactive(ctx: ChannelHandlerContext?) { - super.channelInactive(ctx) - handlerContext?.close() - } - - fun sendDatagramPacket(obj: Any) { - handlerContext?.writeAndFlush(obj) - } - - fun releasePort() { - handlerContext?.close() - } - - override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) { - receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8)) - } - - abstract fun receivedMessage(data: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt deleted file mode 100644 index bcdeef1..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelInitializer -import io.netty.channel.socket.DatagramChannel -import io.netty.handler.timeout.IdleStateHandler - - -open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) : - ChannelInitializer() { - - override fun initChannel(datagramChannel: DatagramChannel) { - val pipeline = datagramChannel.pipeline() - pipeline.addLast( - IdleStateHandler(12, 15, 0) - ).addLast(handler) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt deleted file mode 100644 index 183945a..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt +++ /dev/null @@ -1,101 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import com.casic.br.operationsite.utils.LocaleConstant -import com.pengxh.kt.lite.utils.SaveKeyValues -import io.netty.bootstrap.Bootstrap -import io.netty.buffer.ByteBuf -import io.netty.buffer.Unpooled -import io.netty.channel.ChannelFuture -import io.netty.channel.ChannelOption -import io.netty.channel.nio.NioEventLoopGroup -import io.netty.channel.socket.DatagramPacket -import io.netty.channel.socket.nio.NioDatagramChannel -import io.netty.util.CharsetUtil -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import java.net.InetSocketAddress -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors - - -class UdpClient : UdpChannelInboundHandler(), Runnable { - - private val bootStrap by lazy { Bootstrap() } - private val eventLoopGroup by lazy { NioEventLoopGroup() } - private val udpChannelInitializer by lazy { UdpChannelInitializer(this) } - private var executorService: ExecutorService - - init { - bootStrap.group(eventLoopGroup) - bootStrap.channel(NioDatagramChannel::class.java) - .option(ChannelOption.SO_RCVBUF, 1024) - .option(ChannelOption.SO_SNDBUF, 1024) - bootStrap.handler(udpChannelInitializer) - - executorService = Executors.newSingleThreadExecutor() - executorService.execute(this) - } - - override fun run() { - try { - val channelFuture: ChannelFuture = bootStrap.bind(LocaleConstant.UDP_PORT).sync() - channelFuture.channel().closeFuture().sync() - } catch (e: InterruptedException) { - e.printStackTrace() - } finally { - eventLoopGroup.shutdownGracefully() - } - } - - fun send(value: String) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value, CharsetUtil.UTF_8), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteArray) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteBuf) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun release() { - releasePort() - } - - override fun receivedMessage(data: String) { - - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt new file mode 100644 index 0000000..0acb367 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt @@ -0,0 +1,19 @@ +package com.casic.br.operationsite.utils.netty.tcp + +interface ISocketListener { + companion object { + const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功 + const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接 + const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败 + } + + /** + * 当接收到系统消息 + */ + fun onMessageResponse(data: ByteArray?) + + /** + * 当连接状态发生变化时调用 + */ + fun onServiceStatusConnectChanged(statusCode: Byte) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt new file mode 100644 index 0000000..d381ce0 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt @@ -0,0 +1,34 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.util.Log +import io.netty.channel.ChannelHandlerContext +import io.netty.channel.SimpleChannelInboundHandler + +class SocketChannelHandle(private val listener: ISocketListener?) : + SimpleChannelInboundHandler() { + + private val kTag = "SocketChannelHandle" + + override fun channelActive(ctx: ChannelHandlerContext) { + super.channelActive(ctx) + Log.d(kTag, "channelActive ===> 连接成功") + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS) + } + + override fun channelInactive(ctx: ChannelHandlerContext) { + super.channelInactive(ctx) + Log.e(kTag, "channelInactive: 连接断开") + } + + override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) { + listener?.onMessageResponse(data) + } + + override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) { + super.exceptionCaught(ctx, cause) + Log.d(kTag, "exceptionCaught ===> $cause") + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR) + cause.printStackTrace() + ctx.close() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt new file mode 100644 index 0000000..dffac03 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt @@ -0,0 +1,153 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.os.SystemClock +import android.util.Log +import io.netty.bootstrap.Bootstrap +import io.netty.channel.* +import io.netty.channel.nio.NioEventLoopGroup +import io.netty.channel.socket.SocketChannel +import io.netty.channel.socket.nio.NioSocketChannel +import io.netty.handler.codec.bytes.ByteArrayDecoder +import io.netty.handler.codec.bytes.ByteArrayEncoder +import io.netty.handler.timeout.IdleStateHandler + +class SocketClient { + + private val kTag = "SocketClient" + + private var host: String? = null + private var port = 8000 + private var nioEventLoopGroup: NioEventLoopGroup? = null + private var channel: Channel? = null + private var listener: ISocketListener? = null + + //现在连接的状态 + var connectStatus = false //判断是否已连接 + private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用 + private var isNeedReconnect = true //是否需要重连 + var isConnecting = false //是否正在连接 + private set + private var reconnectIntervalTime: Long = 15000 //重连的时间 + + //重连时间 + fun setReconnectNum(reconnectNum: Int) { + this.reconnectNum = reconnectNum + } + + fun setReconnectIntervalTime(reconnectIntervalTime: Long) { + this.reconnectIntervalTime = reconnectIntervalTime + } + + fun setSocketListener(listener: ISocketListener?) { + this.listener = listener + } + + fun connect(host: String, port: Int) { + this.host = host + this.port = port + Log.d(kTag, "connect ===> 开始连接TCP服务器") + if (isConnecting) { + return + } + //起个线程 + val clientThread: Thread = object : Thread("client-Netty") { + override fun run() { + super.run() + isNeedReconnect = true + reconnectNum = Int.MAX_VALUE + connectServer() + } + } + clientThread.start() + } + + private fun connectServer() { + synchronized(this@SocketClient) { + var channelFuture: ChannelFuture? = null //连接管理对象 + if (!connectStatus) { + isConnecting = true + nioEventLoopGroup = NioEventLoopGroup() //设置的连接group + val bootstrap = Bootstrap() + bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等 + .channel(NioSocketChannel::class.java) + .option(ChannelOption.TCP_NODELAY, true) //无阻塞 + .option(ChannelOption.SO_KEEPALIVE, true) //长连接 + .option( + ChannelOption.RCVBUF_ALLOCATOR, + AdaptiveRecvByteBufAllocator(5000, 5000, 8000) + ) //接收缓冲区 最小值太小时数据接收不全 + .handler(object : ChannelInitializer() { + override fun initChannel(channel: SocketChannel) { + val pipeline = channel.pipeline() + //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调; + //参数2:代表写套接字超时时间,没进行写会触发写超时回调; + //参数3:将在未执行读取或写入时触发超时回调,0代表不处理; + //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接 + pipeline.addLast(IdleStateHandler(60, 10, 0)) + pipeline.addLast(ByteArrayDecoder()) + pipeline.addLast(ByteArrayEncoder()) + pipeline.addLast(SocketChannelHandle(listener)) + } + }) + try { + //连接监听 + channelFuture = bootstrap.connect(host, port) + .addListener(object : ChannelFutureListener { + override fun operationComplete(channelFuture: ChannelFuture) { + if (channelFuture.isSuccess) { + connectStatus = true + channel = channelFuture.channel() + } else { + Log.e(kTag, "operationComplete: 连接失败") + connectStatus = false + } + isConnecting = false + } + }).sync() + // 等待连接关闭 + channelFuture.channel().closeFuture().sync() + } catch (e: Exception) { + e.printStackTrace() + } finally { + connectStatus = false + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识 + if (null != channelFuture) { + if (channelFuture.channel() != null && channelFuture.channel().isOpen) { + channelFuture.channel().close() + } + } + nioEventLoopGroup?.shutdownGracefully() + reconnect() //重新连接 + } + } + } + } + + //断开连接 + fun disconnect() { + Log.d(kTag, "disconnect ===> 断开连接") + isNeedReconnect = false + nioEventLoopGroup?.shutdownGracefully() + } + + //重新连接 + private fun reconnect() { + if (isNeedReconnect && reconnectNum > 0 && !connectStatus) { + reconnectNum-- + SystemClock.sleep(reconnectIntervalTime) + if (isNeedReconnect && reconnectNum > 0 && !connectStatus) { + Log.d(kTag, "reconnect ===> 重新连接") + connectServer() + } + } + } + + fun sendData(bytes: ByteArray) { + channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future -> + if (!future.isSuccess) { + future.channel().close() + nioEventLoopGroup!!.shutdownGracefully() + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketManager.kt new file mode 100644 index 0000000..8c219d5 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketManager.kt @@ -0,0 +1,59 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.util.Log +import com.casic.br.operationsite.view.MethaneActivity +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class SocketManager private constructor() : ISocketListener { + + private val kTag = "SocketManager" + private var nettyClient: SocketClient = SocketClient() + + companion object { + val get by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() } + } + + fun connectNetty(hostname: String, port: Int) { + Thread { + if (!nettyClient.connectStatus) { + nettyClient.setSocketListener(this) + nettyClient.connect(hostname, port) + } else { + nettyClient.disconnect() + } + }.start() + } + + override fun onMessageResponse(data: ByteArray?) { + + } + + override fun onServiceStatusConnectChanged(statusCode: Byte) { + if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) { + if (nettyClient.connectStatus) { + Log.d(kTag, "连接成功") + MethaneActivity.weakReferenceHandler.sendEmptyMessage(2023072101) + } + } else { + if (!nettyClient.connectStatus) { + Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连") + MethaneActivity.weakReferenceHandler.sendEmptyMessage(2023072102) + } + } + } + + fun send(data: ByteArray) { + CoroutineScope(Dispatchers.Main).launch { + withContext(Dispatchers.IO) { + nettyClient.sendData(data) + } + } + } + + fun close() { + nettyClient.disconnect() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInboundHandler.kt new file mode 100644 index 0000000..02284cc --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInboundHandler.kt @@ -0,0 +1,36 @@ +package com.casic.br.operationsite.utils.netty.udp + +import io.netty.channel.ChannelHandlerContext +import io.netty.channel.SimpleChannelInboundHandler +import io.netty.channel.socket.DatagramPacket +import io.netty.util.CharsetUtil + + +abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() { + + private var handlerContext: ChannelHandlerContext? = null + + override fun channelActive(ctx: ChannelHandlerContext?) { + super.channelActive(ctx) + handlerContext = ctx + } + + override fun channelInactive(ctx: ChannelHandlerContext?) { + super.channelInactive(ctx) + handlerContext?.close() + } + + fun sendDatagramPacket(obj: Any) { + handlerContext?.writeAndFlush(obj) + } + + fun releasePort() { + handlerContext?.close() + } + + override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) { + receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8)) + } + + abstract fun receivedMessage(data: String) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInitializer.kt new file mode 100644 index 0000000..5545b56 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInitializer.kt @@ -0,0 +1,17 @@ +package com.casic.br.operationsite.utils.netty.udp + +import io.netty.channel.ChannelInitializer +import io.netty.channel.socket.DatagramChannel +import io.netty.handler.timeout.IdleStateHandler + + +open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) : + ChannelInitializer() { + + override fun initChannel(datagramChannel: DatagramChannel) { + val pipeline = datagramChannel.pipeline() + pipeline.addLast( + IdleStateHandler(12, 15, 0) + ).addLast(handler) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpClient.kt new file mode 100644 index 0000000..05a1375 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpClient.kt @@ -0,0 +1,71 @@ +package com.casic.br.operationsite.utils.netty.udp + +import com.casic.br.operationsite.utils.LocaleConstant +import com.pengxh.kt.lite.utils.SaveKeyValues +import io.netty.bootstrap.Bootstrap +import io.netty.buffer.Unpooled +import io.netty.channel.ChannelFuture +import io.netty.channel.ChannelOption +import io.netty.channel.nio.NioEventLoopGroup +import io.netty.channel.socket.DatagramPacket +import io.netty.channel.socket.nio.NioDatagramChannel +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.net.InetSocketAddress +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors + + +class UdpClient : UdpChannelInboundHandler(), Runnable { + + private val bootStrap by lazy { Bootstrap() } + private val eventLoopGroup by lazy { NioEventLoopGroup() } + private val udpChannelInitializer by lazy { UdpChannelInitializer(this) } + private var executorService: ExecutorService + + init { + bootStrap.group(eventLoopGroup) + bootStrap.channel(NioDatagramChannel::class.java) + .option(ChannelOption.SO_RCVBUF, 1024) + .option(ChannelOption.SO_SNDBUF, 1024) + bootStrap.handler(udpChannelInitializer) + + executorService = Executors.newSingleThreadExecutor() + executorService.execute(this) + } + + override fun run() { + try { + val channelFuture: ChannelFuture = bootStrap.bind(LocaleConstant.UDP_PORT).sync() + channelFuture.channel().closeFuture().sync() + } catch (e: InterruptedException) { + e.printStackTrace() + } finally { + eventLoopGroup.shutdownGracefully() + } + } + + fun send(value: ByteArray) { + CoroutineScope(Dispatchers.Main).launch { + withContext(Dispatchers.IO) { + val host = + SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() + val datagramPacket = DatagramPacket( + Unpooled.copiedBuffer(value), + InetSocketAddress(host, LocaleConstant.UDP_PORT) + ) + sendDatagramPacket(datagramPacket) + } + } + } + + fun release() { + releasePort() + } + + override fun receivedMessage(data: String) { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/view/MethaneActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/MethaneActivity.kt index 0e34bff..26c0f8d 100644 --- a/app/src/main/java/com/casic/br/operationsite/view/MethaneActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/view/MethaneActivity.kt @@ -8,13 +8,15 @@ import android.net.wifi.WifiNetworkSpecifier import android.os.Build import android.os.Bundle +import android.os.Handler +import android.os.Message import androidx.lifecycle.ViewModelProvider import com.casic.br.operationsite.R import com.casic.br.operationsite.extensions.* import com.casic.br.operationsite.utils.DeviceType import com.casic.br.operationsite.utils.LocaleConstant import com.casic.br.operationsite.utils.RuntimeCache -import com.casic.br.operationsite.utils.netty.UdpClient +import com.casic.br.operationsite.utils.netty.tcp.SocketManager import com.casic.br.operationsite.vm.AlarmViewModel import com.casic.br.operationsite.vm.DeviceViewModel import com.gyf.immersionbar.ImmersionBar @@ -23,6 +25,7 @@ import com.pengxh.kt.lite.extensions.getSystemService import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.SteeringWheelController import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.BottomActionSheet @@ -30,12 +33,15 @@ import kotlinx.android.synthetic.main.include_option_title.* -class MethaneActivity : KotlinBaseActivity() { +class MethaneActivity : KotlinBaseActivity(), Handler.Callback { + + companion object { + lateinit var weakReferenceHandler: WeakReferenceHandler + } private val kTag = "MethaneActivity" private val context = this@MethaneActivity private val wifiManager by lazy { getSystemService() } - private val udpClient by lazy { UdpClient() } private val wifiSsids = ArrayList() private val gasTreeItems = ArrayList() private var connectivityManager: ConnectivityManager? = null @@ -49,6 +55,8 @@ private var isActionUp = true override fun initData(savedInstanceState: Bundle?) { + weakReferenceHandler = WeakReferenceHandler(this) + RuntimeCache.deviceModels.forEach { if (it.deviceType == DeviceType.GAS) { gasTreeItems.add("${it.host}:${it.port}") @@ -86,14 +94,26 @@ } } + override fun handleMessage(msg: Message): Boolean { + if (msg.what == 2023072101) { + tcpStateView.setBackgroundColor(R.color.greenColor.convertColor(this)) + rightOptionView.text = "已连接" + } else if (msg.what == 2023072102) { + tcpStateView.setBackgroundColor(R.color.redTextColor.convertColor(this)) + rightOptionView.text = "已断开" + } + return true + } + override fun initEvent() { leftBackView.setOnClickListener { finish() } + //连接TCP rightOptionView.setOnClickListener { - val host = SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() + val host = SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.139").toString() AlertInputDialog.Builder() .setContext(this) - .setTitle("设置设备指令接收地址") + .setTitle("请输入一体机IP地址") .setHintMessage(host) .setNegativeButton("取消") .setPositiveButton("确定") @@ -101,6 +121,8 @@ AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { SaveKeyValues.putValue(LocaleConstant.UDP_HOST, value) + + SocketManager.get.connectNetty(value, LocaleConstant.TCP_PORT) } override fun onCancelClick() {} @@ -175,7 +197,7 @@ dir == SteeringWheelController.Direction.RIGHT || dir == SteeringWheelController.Direction.BOTTOM ) { - udpClient.send(createStopCommand()) + SocketManager.get.send(createStopCommand()) isActionUp = true } else { clickCount++ @@ -193,28 +215,28 @@ override fun onLeftTurn() { if (isActionUp) { - udpClient.send(SteeringWheelController.Direction.LEFT.createStartCommand()) + SocketManager.get.send(SteeringWheelController.Direction.LEFT.createStartCommand()) isActionUp = false } } override fun onTopTurn() { if (isActionUp) { - udpClient.send(SteeringWheelController.Direction.TOP.createStartCommand()) + SocketManager.get.send(SteeringWheelController.Direction.TOP.createStartCommand()) isActionUp = false } } override fun onRightTurn() { if (isActionUp) { - udpClient.send(SteeringWheelController.Direction.RIGHT.createStartCommand()) + SocketManager.get.send(SteeringWheelController.Direction.RIGHT.createStartCommand()) isActionUp = false } } override fun onBottomTurn() { if (isActionUp) { - udpClient.send(SteeringWheelController.Direction.BOTTOM.createStartCommand()) + SocketManager.get.send(SteeringWheelController.Direction.BOTTOM.createStartCommand()) isActionUp = false } } @@ -222,11 +244,11 @@ } private fun closeInstructionsLight() { - udpClient.send(createCloseLightCommand()) + SocketManager.get.send(createCloseLightCommand()) } private fun openInstructionsLight() { - udpClient.send(createOpenLightCommand()) + SocketManager.get.send(createOpenLightCommand()) } private val networkCallback = object : ConnectivityManager.NetworkCallback() { @@ -252,11 +274,10 @@ initLayoutImmersionBar(rootView) titleView.text = "云台参数" - rightOptionView.text = "其他" } override fun onDestroy() { - udpClient.release() + SocketManager.get.close() connectivityManager?.bindProcessToNetwork(null) connectivityManager?.unregisterNetworkCallback(networkCallback) super.onDestroy() diff --git a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt index 1db4e7c..f50c0f7 100644 --- a/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/operationsite/utils/LocaleConstant.kt @@ -34,4 +34,5 @@ const val WIFI_PASSWORD = "zhsz20311hw" const val UDP_HOST = "udpServer" const val UDP_PORT = 9000 + const val TCP_PORT = 9000 } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt deleted file mode 100644 index a7f9d27..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInboundHandler.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelHandlerContext -import io.netty.channel.SimpleChannelInboundHandler -import io.netty.channel.socket.DatagramPacket -import io.netty.util.CharsetUtil - - -abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() { - - private var handlerContext: ChannelHandlerContext? = null - - override fun channelActive(ctx: ChannelHandlerContext?) { - super.channelActive(ctx) - handlerContext = ctx - } - - override fun channelInactive(ctx: ChannelHandlerContext?) { - super.channelInactive(ctx) - handlerContext?.close() - } - - fun sendDatagramPacket(obj: Any) { - handlerContext?.writeAndFlush(obj) - } - - fun releasePort() { - handlerContext?.close() - } - - override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) { - receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8)) - } - - abstract fun receivedMessage(data: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt deleted file mode 100644 index bcdeef1..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpChannelInitializer.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import io.netty.channel.ChannelInitializer -import io.netty.channel.socket.DatagramChannel -import io.netty.handler.timeout.IdleStateHandler - - -open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) : - ChannelInitializer() { - - override fun initChannel(datagramChannel: DatagramChannel) { - val pipeline = datagramChannel.pipeline() - pipeline.addLast( - IdleStateHandler(12, 15, 0) - ).addLast(handler) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt deleted file mode 100644 index 183945a..0000000 --- a/app/src/main/java/com/casic/br/operationsite/utils/netty/UdpClient.kt +++ /dev/null @@ -1,101 +0,0 @@ -package com.casic.br.operationsite.utils.netty - -import com.casic.br.operationsite.utils.LocaleConstant -import com.pengxh.kt.lite.utils.SaveKeyValues -import io.netty.bootstrap.Bootstrap -import io.netty.buffer.ByteBuf -import io.netty.buffer.Unpooled -import io.netty.channel.ChannelFuture -import io.netty.channel.ChannelOption -import io.netty.channel.nio.NioEventLoopGroup -import io.netty.channel.socket.DatagramPacket -import io.netty.channel.socket.nio.NioDatagramChannel -import io.netty.util.CharsetUtil -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import java.net.InetSocketAddress -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors - - -class UdpClient : UdpChannelInboundHandler(), Runnable { - - private val bootStrap by lazy { Bootstrap() } - private val eventLoopGroup by lazy { NioEventLoopGroup() } - private val udpChannelInitializer by lazy { UdpChannelInitializer(this) } - private var executorService: ExecutorService - - init { - bootStrap.group(eventLoopGroup) - bootStrap.channel(NioDatagramChannel::class.java) - .option(ChannelOption.SO_RCVBUF, 1024) - .option(ChannelOption.SO_SNDBUF, 1024) - bootStrap.handler(udpChannelInitializer) - - executorService = Executors.newSingleThreadExecutor() - executorService.execute(this) - } - - override fun run() { - try { - val channelFuture: ChannelFuture = bootStrap.bind(LocaleConstant.UDP_PORT).sync() - channelFuture.channel().closeFuture().sync() - } catch (e: InterruptedException) { - e.printStackTrace() - } finally { - eventLoopGroup.shutdownGracefully() - } - } - - fun send(value: String) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value, CharsetUtil.UTF_8), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteArray) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun send(value: ByteBuf) { - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val host = - SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() - val datagramPacket = DatagramPacket( - Unpooled.copiedBuffer(value), - InetSocketAddress(host, LocaleConstant.UDP_PORT) - ) - sendDatagramPacket(datagramPacket) - } - } - } - - fun release() { - releasePort() - } - - override fun receivedMessage(data: String) { - - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt new file mode 100644 index 0000000..0acb367 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/ISocketListener.kt @@ -0,0 +1,19 @@ +package com.casic.br.operationsite.utils.netty.tcp + +interface ISocketListener { + companion object { + const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功 + const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接 + const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败 + } + + /** + * 当接收到系统消息 + */ + fun onMessageResponse(data: ByteArray?) + + /** + * 当连接状态发生变化时调用 + */ + fun onServiceStatusConnectChanged(statusCode: Byte) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt new file mode 100644 index 0000000..d381ce0 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketChannelHandle.kt @@ -0,0 +1,34 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.util.Log +import io.netty.channel.ChannelHandlerContext +import io.netty.channel.SimpleChannelInboundHandler + +class SocketChannelHandle(private val listener: ISocketListener?) : + SimpleChannelInboundHandler() { + + private val kTag = "SocketChannelHandle" + + override fun channelActive(ctx: ChannelHandlerContext) { + super.channelActive(ctx) + Log.d(kTag, "channelActive ===> 连接成功") + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS) + } + + override fun channelInactive(ctx: ChannelHandlerContext) { + super.channelInactive(ctx) + Log.e(kTag, "channelInactive: 连接断开") + } + + override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) { + listener?.onMessageResponse(data) + } + + override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) { + super.exceptionCaught(ctx, cause) + Log.d(kTag, "exceptionCaught ===> $cause") + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR) + cause.printStackTrace() + ctx.close() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt new file mode 100644 index 0000000..dffac03 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketClient.kt @@ -0,0 +1,153 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.os.SystemClock +import android.util.Log +import io.netty.bootstrap.Bootstrap +import io.netty.channel.* +import io.netty.channel.nio.NioEventLoopGroup +import io.netty.channel.socket.SocketChannel +import io.netty.channel.socket.nio.NioSocketChannel +import io.netty.handler.codec.bytes.ByteArrayDecoder +import io.netty.handler.codec.bytes.ByteArrayEncoder +import io.netty.handler.timeout.IdleStateHandler + +class SocketClient { + + private val kTag = "SocketClient" + + private var host: String? = null + private var port = 8000 + private var nioEventLoopGroup: NioEventLoopGroup? = null + private var channel: Channel? = null + private var listener: ISocketListener? = null + + //现在连接的状态 + var connectStatus = false //判断是否已连接 + private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用 + private var isNeedReconnect = true //是否需要重连 + var isConnecting = false //是否正在连接 + private set + private var reconnectIntervalTime: Long = 15000 //重连的时间 + + //重连时间 + fun setReconnectNum(reconnectNum: Int) { + this.reconnectNum = reconnectNum + } + + fun setReconnectIntervalTime(reconnectIntervalTime: Long) { + this.reconnectIntervalTime = reconnectIntervalTime + } + + fun setSocketListener(listener: ISocketListener?) { + this.listener = listener + } + + fun connect(host: String, port: Int) { + this.host = host + this.port = port + Log.d(kTag, "connect ===> 开始连接TCP服务器") + if (isConnecting) { + return + } + //起个线程 + val clientThread: Thread = object : Thread("client-Netty") { + override fun run() { + super.run() + isNeedReconnect = true + reconnectNum = Int.MAX_VALUE + connectServer() + } + } + clientThread.start() + } + + private fun connectServer() { + synchronized(this@SocketClient) { + var channelFuture: ChannelFuture? = null //连接管理对象 + if (!connectStatus) { + isConnecting = true + nioEventLoopGroup = NioEventLoopGroup() //设置的连接group + val bootstrap = Bootstrap() + bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等 + .channel(NioSocketChannel::class.java) + .option(ChannelOption.TCP_NODELAY, true) //无阻塞 + .option(ChannelOption.SO_KEEPALIVE, true) //长连接 + .option( + ChannelOption.RCVBUF_ALLOCATOR, + AdaptiveRecvByteBufAllocator(5000, 5000, 8000) + ) //接收缓冲区 最小值太小时数据接收不全 + .handler(object : ChannelInitializer() { + override fun initChannel(channel: SocketChannel) { + val pipeline = channel.pipeline() + //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调; + //参数2:代表写套接字超时时间,没进行写会触发写超时回调; + //参数3:将在未执行读取或写入时触发超时回调,0代表不处理; + //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接 + pipeline.addLast(IdleStateHandler(60, 10, 0)) + pipeline.addLast(ByteArrayDecoder()) + pipeline.addLast(ByteArrayEncoder()) + pipeline.addLast(SocketChannelHandle(listener)) + } + }) + try { + //连接监听 + channelFuture = bootstrap.connect(host, port) + .addListener(object : ChannelFutureListener { + override fun operationComplete(channelFuture: ChannelFuture) { + if (channelFuture.isSuccess) { + connectStatus = true + channel = channelFuture.channel() + } else { + Log.e(kTag, "operationComplete: 连接失败") + connectStatus = false + } + isConnecting = false + } + }).sync() + // 等待连接关闭 + channelFuture.channel().closeFuture().sync() + } catch (e: Exception) { + e.printStackTrace() + } finally { + connectStatus = false + listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识 + if (null != channelFuture) { + if (channelFuture.channel() != null && channelFuture.channel().isOpen) { + channelFuture.channel().close() + } + } + nioEventLoopGroup?.shutdownGracefully() + reconnect() //重新连接 + } + } + } + } + + //断开连接 + fun disconnect() { + Log.d(kTag, "disconnect ===> 断开连接") + isNeedReconnect = false + nioEventLoopGroup?.shutdownGracefully() + } + + //重新连接 + private fun reconnect() { + if (isNeedReconnect && reconnectNum > 0 && !connectStatus) { + reconnectNum-- + SystemClock.sleep(reconnectIntervalTime) + if (isNeedReconnect && reconnectNum > 0 && !connectStatus) { + Log.d(kTag, "reconnect ===> 重新连接") + connectServer() + } + } + } + + fun sendData(bytes: ByteArray) { + channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future -> + if (!future.isSuccess) { + future.channel().close() + nioEventLoopGroup!!.shutdownGracefully() + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketManager.kt new file mode 100644 index 0000000..8c219d5 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/tcp/SocketManager.kt @@ -0,0 +1,59 @@ +package com.casic.br.operationsite.utils.netty.tcp + +import android.util.Log +import com.casic.br.operationsite.view.MethaneActivity +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class SocketManager private constructor() : ISocketListener { + + private val kTag = "SocketManager" + private var nettyClient: SocketClient = SocketClient() + + companion object { + val get by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() } + } + + fun connectNetty(hostname: String, port: Int) { + Thread { + if (!nettyClient.connectStatus) { + nettyClient.setSocketListener(this) + nettyClient.connect(hostname, port) + } else { + nettyClient.disconnect() + } + }.start() + } + + override fun onMessageResponse(data: ByteArray?) { + + } + + override fun onServiceStatusConnectChanged(statusCode: Byte) { + if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) { + if (nettyClient.connectStatus) { + Log.d(kTag, "连接成功") + MethaneActivity.weakReferenceHandler.sendEmptyMessage(2023072101) + } + } else { + if (!nettyClient.connectStatus) { + Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连") + MethaneActivity.weakReferenceHandler.sendEmptyMessage(2023072102) + } + } + } + + fun send(data: ByteArray) { + CoroutineScope(Dispatchers.Main).launch { + withContext(Dispatchers.IO) { + nettyClient.sendData(data) + } + } + } + + fun close() { + nettyClient.disconnect() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInboundHandler.kt new file mode 100644 index 0000000..02284cc --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInboundHandler.kt @@ -0,0 +1,36 @@ +package com.casic.br.operationsite.utils.netty.udp + +import io.netty.channel.ChannelHandlerContext +import io.netty.channel.SimpleChannelInboundHandler +import io.netty.channel.socket.DatagramPacket +import io.netty.util.CharsetUtil + + +abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() { + + private var handlerContext: ChannelHandlerContext? = null + + override fun channelActive(ctx: ChannelHandlerContext?) { + super.channelActive(ctx) + handlerContext = ctx + } + + override fun channelInactive(ctx: ChannelHandlerContext?) { + super.channelInactive(ctx) + handlerContext?.close() + } + + fun sendDatagramPacket(obj: Any) { + handlerContext?.writeAndFlush(obj) + } + + fun releasePort() { + handlerContext?.close() + } + + override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) { + receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8)) + } + + abstract fun receivedMessage(data: String) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInitializer.kt new file mode 100644 index 0000000..5545b56 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpChannelInitializer.kt @@ -0,0 +1,17 @@ +package com.casic.br.operationsite.utils.netty.udp + +import io.netty.channel.ChannelInitializer +import io.netty.channel.socket.DatagramChannel +import io.netty.handler.timeout.IdleStateHandler + + +open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) : + ChannelInitializer() { + + override fun initChannel(datagramChannel: DatagramChannel) { + val pipeline = datagramChannel.pipeline() + pipeline.addLast( + IdleStateHandler(12, 15, 0) + ).addLast(handler) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpClient.kt b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpClient.kt new file mode 100644 index 0000000..05a1375 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/utils/netty/udp/UdpClient.kt @@ -0,0 +1,71 @@ +package com.casic.br.operationsite.utils.netty.udp + +import com.casic.br.operationsite.utils.LocaleConstant +import com.pengxh.kt.lite.utils.SaveKeyValues +import io.netty.bootstrap.Bootstrap +import io.netty.buffer.Unpooled +import io.netty.channel.ChannelFuture +import io.netty.channel.ChannelOption +import io.netty.channel.nio.NioEventLoopGroup +import io.netty.channel.socket.DatagramPacket +import io.netty.channel.socket.nio.NioDatagramChannel +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.net.InetSocketAddress +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors + + +class UdpClient : UdpChannelInboundHandler(), Runnable { + + private val bootStrap by lazy { Bootstrap() } + private val eventLoopGroup by lazy { NioEventLoopGroup() } + private val udpChannelInitializer by lazy { UdpChannelInitializer(this) } + private var executorService: ExecutorService + + init { + bootStrap.group(eventLoopGroup) + bootStrap.channel(NioDatagramChannel::class.java) + .option(ChannelOption.SO_RCVBUF, 1024) + .option(ChannelOption.SO_SNDBUF, 1024) + bootStrap.handler(udpChannelInitializer) + + executorService = Executors.newSingleThreadExecutor() + executorService.execute(this) + } + + override fun run() { + try { + val channelFuture: ChannelFuture = bootStrap.bind(LocaleConstant.UDP_PORT).sync() + channelFuture.channel().closeFuture().sync() + } catch (e: InterruptedException) { + e.printStackTrace() + } finally { + eventLoopGroup.shutdownGracefully() + } + } + + fun send(value: ByteArray) { + CoroutineScope(Dispatchers.Main).launch { + withContext(Dispatchers.IO) { + val host = + SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() + val datagramPacket = DatagramPacket( + Unpooled.copiedBuffer(value), + InetSocketAddress(host, LocaleConstant.UDP_PORT) + ) + sendDatagramPacket(datagramPacket) + } + } + } + + fun release() { + releasePort() + } + + override fun receivedMessage(data: String) { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/view/MethaneActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/MethaneActivity.kt index 0e34bff..26c0f8d 100644 --- a/app/src/main/java/com/casic/br/operationsite/view/MethaneActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/view/MethaneActivity.kt @@ -8,13 +8,15 @@ import android.net.wifi.WifiNetworkSpecifier import android.os.Build import android.os.Bundle +import android.os.Handler +import android.os.Message import androidx.lifecycle.ViewModelProvider import com.casic.br.operationsite.R import com.casic.br.operationsite.extensions.* import com.casic.br.operationsite.utils.DeviceType import com.casic.br.operationsite.utils.LocaleConstant import com.casic.br.operationsite.utils.RuntimeCache -import com.casic.br.operationsite.utils.netty.UdpClient +import com.casic.br.operationsite.utils.netty.tcp.SocketManager import com.casic.br.operationsite.vm.AlarmViewModel import com.casic.br.operationsite.vm.DeviceViewModel import com.gyf.immersionbar.ImmersionBar @@ -23,6 +25,7 @@ import com.pengxh.kt.lite.extensions.getSystemService import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.SteeringWheelController import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.BottomActionSheet @@ -30,12 +33,15 @@ import kotlinx.android.synthetic.main.include_option_title.* -class MethaneActivity : KotlinBaseActivity() { +class MethaneActivity : KotlinBaseActivity(), Handler.Callback { + + companion object { + lateinit var weakReferenceHandler: WeakReferenceHandler + } private val kTag = "MethaneActivity" private val context = this@MethaneActivity private val wifiManager by lazy { getSystemService() } - private val udpClient by lazy { UdpClient() } private val wifiSsids = ArrayList() private val gasTreeItems = ArrayList() private var connectivityManager: ConnectivityManager? = null @@ -49,6 +55,8 @@ private var isActionUp = true override fun initData(savedInstanceState: Bundle?) { + weakReferenceHandler = WeakReferenceHandler(this) + RuntimeCache.deviceModels.forEach { if (it.deviceType == DeviceType.GAS) { gasTreeItems.add("${it.host}:${it.port}") @@ -86,14 +94,26 @@ } } + override fun handleMessage(msg: Message): Boolean { + if (msg.what == 2023072101) { + tcpStateView.setBackgroundColor(R.color.greenColor.convertColor(this)) + rightOptionView.text = "已连接" + } else if (msg.what == 2023072102) { + tcpStateView.setBackgroundColor(R.color.redTextColor.convertColor(this)) + rightOptionView.text = "已断开" + } + return true + } + override fun initEvent() { leftBackView.setOnClickListener { finish() } + //连接TCP rightOptionView.setOnClickListener { - val host = SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.133").toString() + val host = SaveKeyValues.getValue(LocaleConstant.UDP_HOST, "192.168.10.139").toString() AlertInputDialog.Builder() .setContext(this) - .setTitle("设置设备指令接收地址") + .setTitle("请输入一体机IP地址") .setHintMessage(host) .setNegativeButton("取消") .setPositiveButton("确定") @@ -101,6 +121,8 @@ AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { SaveKeyValues.putValue(LocaleConstant.UDP_HOST, value) + + SocketManager.get.connectNetty(value, LocaleConstant.TCP_PORT) } override fun onCancelClick() {} @@ -175,7 +197,7 @@ dir == SteeringWheelController.Direction.RIGHT || dir == SteeringWheelController.Direction.BOTTOM ) { - udpClient.send(createStopCommand()) + SocketManager.get.send(createStopCommand()) isActionUp = true } else { clickCount++ @@ -193,28 +215,28 @@ override fun onLeftTurn() { if (isActionUp) { - udpClient.send(SteeringWheelController.Direction.LEFT.createStartCommand()) + SocketManager.get.send(SteeringWheelController.Direction.LEFT.createStartCommand()) isActionUp = false } } override fun onTopTurn() { if (isActionUp) { - udpClient.send(SteeringWheelController.Direction.TOP.createStartCommand()) + SocketManager.get.send(SteeringWheelController.Direction.TOP.createStartCommand()) isActionUp = false } } override fun onRightTurn() { if (isActionUp) { - udpClient.send(SteeringWheelController.Direction.RIGHT.createStartCommand()) + SocketManager.get.send(SteeringWheelController.Direction.RIGHT.createStartCommand()) isActionUp = false } } override fun onBottomTurn() { if (isActionUp) { - udpClient.send(SteeringWheelController.Direction.BOTTOM.createStartCommand()) + SocketManager.get.send(SteeringWheelController.Direction.BOTTOM.createStartCommand()) isActionUp = false } } @@ -222,11 +244,11 @@ } private fun closeInstructionsLight() { - udpClient.send(createCloseLightCommand()) + SocketManager.get.send(createCloseLightCommand()) } private fun openInstructionsLight() { - udpClient.send(createOpenLightCommand()) + SocketManager.get.send(createOpenLightCommand()) } private val networkCallback = object : ConnectivityManager.NetworkCallback() { @@ -252,11 +274,10 @@ initLayoutImmersionBar(rootView) titleView.text = "云台参数" - rightOptionView.text = "其他" } override fun onDestroy() { - udpClient.release() + SocketManager.get.close() connectivityManager?.bindProcessToNetwork(null) connectivityManager?.unregisterNetworkCallback(networkCallback) super.onDestroy() diff --git a/app/src/main/res/layout/activity_methane.xml b/app/src/main/res/layout/activity_methane.xml index 8063b91..8b10f0b 100644 --- a/app/src/main/res/layout/activity_methane.xml +++ b/app/src/main/res/layout/activity_methane.xml @@ -18,14 +18,29 @@ android:background="@drawable/bg_solid_layout_white_radius_10" android:orientation="vertical"> - + android:layout_height="@dimen/titleViewHeight"> + + + + +