package com.anyun.exam.lib.net
|
|
import android.content.Context
|
import android.util.Log
|
import io.netty.bootstrap.Bootstrap
|
import io.netty.buffer.Unpooled
|
import io.netty.channel.Channel
|
import io.netty.channel.ChannelFutureListener
|
import io.netty.channel.ChannelInitializer
|
import io.netty.channel.ChannelOption
|
import io.netty.channel.nio.NioEventLoopGroup
|
import io.netty.channel.socket.nio.NioSocketChannel
|
import io.netty.handler.codec.DelimiterBasedFrameDecoder
|
import io.netty.handler.logging.LogLevel
|
import io.netty.handler.logging.LoggingHandler
|
import io.netty.handler.timeout.IdleStateHandler
|
import io.netty.util.AttributeKey
|
import java.util.concurrent.TimeUnit
|
|
abstract class NettyTcpClient(var session: TcpSession) {
|
val KEY = AttributeKey.valueOf<NettyTcpClient>("TcpClient")
|
private var bootstrap: Bootstrap = Bootstrap()
|
private val group = NioEventLoopGroup()
|
|
var isAuthentication = false
|
var dataStatus = WAIT_AUTH
|
/**
|
* tcp链接成功标志
|
*/
|
var isConnected = false
|
lateinit var host: String
|
var port: Int = 0
|
var autoConnect = false
|
lateinit var context: Context
|
internal var channel: Channel? = null
|
|
companion object {
|
public val WAIT_AUTH = 0
|
public val BODY = 1
|
}
|
|
init {
|
bootstrap.group(group)
|
.channel(NioSocketChannel::class.java)
|
.option(ChannelOption.SO_KEEPALIVE, true)
|
.handler(LoggingHandler(LogLevel.INFO))
|
|
bootstrap.handler(object : ChannelInitializer<Channel>() {
|
//初始化channel
|
override fun initChannel(ch: Channel) {
|
ch.pipeline().addLast(
|
DelimiterBasedFrameDecoder(
|
2048,
|
false,
|
Unpooled.copiedBuffer(byteArrayOf(0x0D, 0x0A))
|
)
|
)
|
ch.pipeline().addLast(IdleStateHandler(60, 30, 0, TimeUnit.SECONDS))
|
ch.pipeline().addLast(ConnectorIdleStateTrigger())
|
ch.pipeline().addLast(ConnectionWatchdog())
|
ch.pipeline().addLast(NtripDecoder())
|
ch.pipeline().addLast(NtripEncoder())
|
ch.pipeline().addLast(MessageHandler())
|
ch.pipeline().addLast(ExceptionHandler())
|
}
|
})
|
}
|
|
fun connect(context: Context) {
|
this.context = context
|
this.connect(session.ip, session.port)
|
}
|
|
@Synchronized private fun connect(host: String, port: Int) {
|
Log.i(Constant.LOGTAG, "连接TCP ${host}:${port} ${KEY.name()}...")
|
this.host = host
|
this.port = port
|
|
if(channel!=null && channel!!.isOpen)
|
{
|
Log.i(Constant.LOGTAG, "Close先前的连接")
|
close(false)
|
}
|
var future = bootstrap.connect(host, port)
|
future.addListener(CONNECT_END_HANDLER)
|
channel = future.channel()
|
}
|
|
private val CONNECT_END_HANDLER = ChannelFutureListener {
|
if (!it.isSuccess) {
|
Log.i(Constant.LOGTAG, "连接服务器失败$host:$port 等待5秒重新连接")
|
it.channel().pipeline().fireExceptionCaught(it.cause())
|
Thread.sleep(5000)
|
|
if (!isConnected) {
|
this.connect(this.context)
|
} else {
|
|
}
|
}
|
else
|
{
|
isConnected = true
|
it.channel().attr(KEY).set(this)
|
}
|
}
|
|
fun close(auto_connect: Boolean) {
|
try {
|
autoConnect = auto_connect;
|
if(channel!=null && channel!!.isOpen) {
|
channel!!.close();
|
//这句一直阻塞 原因未知
|
//closeFuture().sync();
|
}
|
}
|
catch (ex: Exception)
|
{
|
|
}
|
}
|
|
fun writeAndFlush(cmdstr: String): Boolean {
|
if (!isConnected) {
|
Log.d(Constant.LOGTAG, "TCP未连接")
|
return false
|
}
|
|
System.out.println("发送数据<${host}:${port}> = " + cmdstr)
|
|
channel!!.writeAndFlush(cmdstr)
|
return true
|
}
|
}
|