yy1717
2024-02-28 27fc91fbe8f88b6885356e68828cfe1ce1db7601
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
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
    }
}