用kotlin编写基于物联网长连接通信架构服务-模板

30 篇文章 0 订阅
28 篇文章 0 订阅

多台4G信号设备(如ofo)连接到指定服务器的一套架构

工程类型 idea-kotlin

资源下载 1-客户端UI下载 2-服务器UI下载   3-代码下载

硬件定时发送心跳给服务器 建立连接 多台移动设备通过服务器控制设备或者查状态
该需求有点类似多人聊天室 就比如ofo一样多个用户和多个设备之间处理

以队列安全的形势查询和控制准确发出指令和接收指令

设备长连接就可以套用该模板设计各种命令提供第三方调用,至于硬件指令都可以通过模板在衍生出来从而解决各种需求

这里用软件客户端模拟硬件测试(包括16进制编码传输),

 

测试效果图如下

发送心跳"1" 与设备建立连接

自定义命令 $php-> IsLive 1  (1是连接的设备名) 是否已连接

自定义命令 $php-> SearchList 查询当前连接的服务器列表

开启服务后 发送设备号“2” 发送 2 心跳与设备建立连接

发送自定义命令 $php-> Receive 2 “等待接收数据”  (等待设备2回传数据)

如果设备2不响应时超时会提示code 1002

多次发送指令会按顺序加入队列依次返回数据

在响应时间内 设备2返回数据时会返回指令发起端。

原理:

名称解释:
App->手机app
Servce->Http服务器或第三方平台
TcpScrit->一个脚本服务提供给Service调用
Device->4G设备

 

模板设计的技术难点在于如何解决异步和多台设备通信
保证每个设备都收到一条信息和回传的信息能够准确的回传给发起端

通常4G设备会不断发送心跳给服务器上的脚本
2:服务器将设备加入到连接的列表中
3:服务向设备应答回传信息
之所以用脚本因为它可能会被其他服务或者其他语言调用,如下图

单个移动设备请求单个物联网设备从发起到结束的时序图如下

1:一个App端向第三方后台发送http请求

2:后台收到请求后向脚本发出指令

3:脚本发送指令(单向或者双向等待回传)给设备

4:脚本响应回传后台是否成功

5:后台返回app端数据

 

当有多个用户和多台设备时多并发的问题就来了

1:如果多个app端对同一台设备发起操作和查询指令 如何保证每一个设备的查询是正确的并且不会串联

2:如果有一台设备没有响应了,如何作出超时处理

关于这点可以使用队列的来区分每一次的请求,这里默认是长连接的方式如下图所示

流程如下:

⓪多台设备发送心跳给服务器从而建立连接

①服务器接收到某个http请求向脚本发起指令

②定义多个指令类型的集合,根据是哪一条指令类型作后续动作,如果是需要监听回调信息还会注册某个设备的监听器

③将指令在超时队列中运行

④向4G设备发送控制或者查询指令

⑤4G设备向脚本回传当前自己的状态,进入⑥流程

⑥设备监听器接收到指定设备回传的消息作动作

⑦继续回到队列流程处理-如果没有数据就做出超时处理

⑧向服务端回传数据

从一个请求发起到结束可以看作一次事件 以下类图是每个流程需要实现的方法

首先是服务器和多个设备如何建立连接

package org.lxz.tools.syncdevice.client

import org.lxz.tools.syncdevice.event.*
import org.lxz.tools.syncdevice.helper.HexHelper
import java.io.*
import java.net.*
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.locks.ReentrantLock

/**
 * Created by linxingzhu on 2018/6/28.
 */
interface DeviceConnectListListen {
    fun list(connectMap:HashMap<String, DeviceConnect>)
    fun addDevice(deviceConn: DeviceConnect)
    fun remove(deviceConn: DeviceConnect)
}

interface LogListen{
    /**输入与触发事件监听*/
    fun received(received:String, hex:String, device: DeviceConnect, event:EventTask, code:Int)
    /**输出监听*/
    fun write(connect: DeviceConnect, send:String, mode: OutPutSteamMode)
}


interface ServiceEventListen{
    fun event(code:Int)
}
enum class OutPutSteamMode(val desc: String) {
    DEFAULT("字符串形式"),
    HEX("16进制形式");


}
class TcpService private constructor():Runnable {

    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            instaince.startServer(arrayListOf(
                    HeartbeatEventTask::class.java,
                    OpenLockEventTask::class.java,
                    CheckStatusEventTask::class.java,
                    CheckAllLockStatusEventTask::class.java,
                    SearchConnectListEventTask::class.java,
                    IsLiveEventTask::class.java
            ))
        }

        val instaince: TcpService by lazy{ TcpService() }


        const val ERROR_STATUS="error"
        const val SUCCESS_STATUS="success"
        const val ERROR_CODE_INTERRRUPTED=1001
        const val ERROR_CODE_TIME_OUT=1002
        const val ERROR_CODE_CANNET_NOT_CALLBACK_DATA=1003
        const val ERROR_CODE_CANNET_NOT_FIND_DEVICE=1004
        /**处理*/
        const val STATUS_CODE_DISPOSE=10
        const val STATUS_CODE_ACCEPT=11
        const val STATUS_CODE_ACCEPT_BUT_NOT_CALLBACK_DATA=12
        const val STATUS_CODE_DISPOSE_BUT_NOT_CALLBACK_DATA=13

        const val EVENT_INIT_CODE=9001;
        const val EVENT_CLOSE_CODE=9002
    }
    var deviceConnectThreaadPool: ExecutorService?=null
    val version = "1.2"
    val port = 9501
    /**异步读写锁*/
    val synclock = ReentrantLock()

    var eventChainTask = arrayListOf<Class<out EventAction>>()




    /**TCP服务设备连接列表*/
    val connectDeviceMap = HashMap<String, DeviceConnect>()
    /**TCP服务非设备列表*/
    val connecNonDeviceList= arrayListOf<DeviceConnect>()

    init{println("Build TcpService Version:" + version +" port:"+port) }

    private var mDeviceConnectListListen: DeviceConnectListListen?=null
    fun setDeviceConnectListListen(deviceConn: DeviceConnectListListen?): TcpService {
        mDeviceConnectListListen=deviceConn
        return this
    }
    fun getDeviceConnectListListen(): DeviceConnectListListen?=mDeviceConnectListListen
    private var mLogListen: LogListen?=null
    fun setLogListen(log: LogListen): TcpService {
        mLogListen=log
        return this
    }
    fun getLogListen(): LogListen?=mLogListen

    private var mServiceEventListen: ServiceEventListen?=null
    fun setServiceEventListen(event: ServiceEventListen): TcpService {
        mServiceEventListen=event
        return this
    }
    fun getServiceEventListen(): ServiceEventListen?=mServiceEventListen


    /**创建一条本地指令*/
    fun command(content:String,mode: OutPutSteamMode,listen:DeviceConnect.ReadDataListen){
        var conn=DeviceConnect(Socket("127.0.0.1",port))
        conn.setReadDataListen(listen)
        write(conn,content,mode)

    }



    fun syncExecute(action:()->Unit){
        try {
            synclock.lock()
            action()
            synclock.unlock()
        } catch (e: Exception) {
        }

    }
    fun write(connect: DeviceConnect, content:String, mode: OutPutSteamMode)
    {
        syncExecute {
            when(mode)
            {
                OutPutSteamMode.DEFAULT ->{
                    connect.printWriter.write(content)
                    connect.printWriter.flush()
                }
                OutPutSteamMode.HEX ->{
                    var bytes=HexHelper.hexStr2Bytes(content)
                    connect.outStream.write(bytes)
                    connect.printWriter.flush()
                }
            }
            mLogListen?.write(connect,content,mode);
        }

    }





    fun startServer(clazzs:List<Class<out EventAction>>) {
        eventChainTask.clear()
        eventChainTask.addAll(clazzs)
        println("TCP端口监听启动")
        serverSocket?.close()
        if(deviceConnectThreaadPool==null||deviceConnectThreaadPool!!.isShutdown)
        {
            deviceConnectThreaadPool = Executors.newWorkStealingPool()
        }
        deviceConnectThreaadPool!!.submit(this)

    }

    var serverSocket: ServerSocket?=null

    override fun run() {
        try {
            var socket: Socket? = null
            serverSocket = ServerSocket(port)// 1024-65535的某个端口
            // 调用accept()方法开始监听,等待客户端的连接
            fun getSocket(): Socket? {
                    socket = serverSocket!!.accept()

                return socket;
            }
            mServiceEventListen?.event(EVENT_INIT_CODE)
            while (serverSocket!=null&&!(serverSocket!!.isClosed)&&getSocket() != null) {
                println("服务器监听到新连接:" + socket!!.inetAddress)
                var deviceConnect:DeviceConnect=DeviceConnect(socket!!)
                addNonDeviceList(deviceConnect)
                deviceConnectThreaadPool?.submit(deviceConnect)
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }
        println("服务器停止监听")
        mServiceEventListen?.event(EVENT_CLOSE_CODE)
    }

    private fun addNonDeviceList(deviceConnect: DeviceConnect) {
        syncExecute {
            connecNonDeviceList.add(deviceConnect)
        }
    }

    fun removeNonDeviceSocketConnectList(deviceConnect: DeviceConnect) {
        syncExecute {
            connecNonDeviceList.remove(deviceConnect)
        }
    }


    fun saveSocketConnectMap(deviceId: String, tcpSocketConnect: DeviceConnect) {
        syncExecute{
            print("添加新设备${deviceId}")
            instaince.connectDeviceMap.put(deviceId, tcpSocketConnect)
            mDeviceConnectListListen?.list(connectDeviceMap)
            connecNonDeviceList.remove(tcpSocketConnect)
            mDeviceConnectListListen?.addDevice(tcpSocketConnect)
        }
    }
    fun removeSocketConnectMap(deviceId: String, tcpSocketConnect: DeviceConnect) {
        syncExecute {
            print("移除设备${deviceId}")
            instaince.connectDeviceMap.remove(deviceId)
            mDeviceConnectListListen?.list(connectDeviceMap)
            mDeviceConnectListListen?.remove(tcpSocketConnect)
        }
    }

    fun stopServect() {
        //关闭所有连接
        closeAllConnect()

        deviceConnectThreaadPool?.shutdownNow()
        serverSocket?.close()
        serverSocket=null;

    }

    private fun closeAllConnect() {
        closeDeviceConnect()
        closeNonDeviceConnect()
    }

    private fun closeNonDeviceConnect() {

      syncExecute {
          var it=connecNonDeviceList.iterator()
          while (it.hasNext())
          {
              it.next().outStream.close()
          }
          connecNonDeviceList.clear()
      }
    }

    private fun closeDeviceConnect() {
        var it=connectDeviceMap.iterator()
        while (it.hasNext())
        {
            it.next().value.outStream.close()
        }
        connectDeviceMap.clear()
    }


}

为每一个连接插件读写流和监听

class DeviceConnect(val socket: Socket) : Runnable {
    var outStream: OutputStream
    var inStream: InputStream
    var reader: BufferedReader
    var deviceId: String? = null
    val createTime: String
    var printWriter: PrintWriter
    var events:ArrayList<EventAction> = arrayListOf()
    interface ReadDataListen{
        fun read(connect: DeviceConnect,message:String,hex:String,byte:ByteArray,length:Int)
    }
    private var mReadDataListen:ReadDataListen?=null

    fun setReadDataListen(listen:ReadDataListen):DeviceConnect
    {   mReadDataListen=listen
        return this }

    fun getReadDataListen():ReadDataListen?=mReadDataListen


    init {
        createTime = TimeHelper.getNowTime()
        outStream = socket.getOutputStream()
        printWriter = PrintWriter(outStream)
        inStream = socket.getInputStream()
        val streamReader = InputStreamReader(inStream)
        reader = BufferedReader(streamReader)
        for(eventClass in TcpService.instaince.eventChainTask)
        {
            events.add(eventClass.newInstance())
        }

    }

    var openEnabledReceiverTask:ArrayList<EventAction> = arrayListOf();

    override fun run() {
        val buffer = ByteArray(1024 * 4)
        var n = 0
        fun read(): Int {
            n = inStream.read(buffer)
            return n;
        }
        while ((read()) != -1) {
            val message = String(buffer, 0, n)
            val instruct = message.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray().toList()
            val hex = HexHelper.byte2HexStr(buffer, n)
            mReadDataListen?.read(this,message,hex,buffer,n);
            println("message:->" + message);
            println("hex:->" + hex);

            TcpService.instaince.syncExecute {
                for (task in openEnabledReceiverTask) {
                    println("当前有一条任务等待回调")
                    task.deviceAcceptTaskInQueue(message, hex, this, TcpService.instaince)
                }
            }


          for(task in  events) {
                var isProcessing = task.receiveProcess(message, hex, instruct)
                if (isProcessing) {
                    task.disposeEventTaskInQueue(message, hex, instruct, this, TcpService.instaince)
                    events.remove(task)
                    events.add(task.javaClass.newInstance())
                    break
                }
            }
        }

        when(deviceId!=null){
            true->TcpService.instaince.removeSocketConnectMap(deviceId!!, this)
            else->TcpService.instaince.removeNonDeviceSocketConnectList(this)
        }
        println("IP:" + socket.inetAddress + " 命令 " + deviceId + " 断开连接")

    }
}

创建一个从发起到接收数据的事件接口

/**一个连接事件到结束的生命周期*/
interface EventAction{
    /**
     * @param message 接收到的原始消息
     * @param hex 转化成16进制
     * @param instruct 转化以空格分割开的指令
     */
    fun receiveProcess(message:String,hex:String, instruct:List<String>):Boolean


    /**设置超时时间*/
    fun timeOut():Long

    /**返回第一个连接的客户端*/
    fun getFristConnectClient(): DeviceConnect


    /**返回待监听的客户端*/
    fun getAcceptConnectClient(): DeviceConnect?


    /**
     * @param cmd 接收的指令
     * @param client 当前发送消息的设备
     * @param connectList 已连接设备服务列表
     */
    fun disposeEvent(message:String, hex:String, instruct:List<String>, client: DeviceConnect, service: TcpService)


    /**监听指定的设备*/
    fun deviceAccept(receive:String, hex:String, client: DeviceConnect, service: TcpService)

    /**加入超时队列-处理第一个连接的设备指令*/
    fun disposeEventTaskInQueue(message: String, hex: String, instruct: List<String>, client: DeviceConnect, service: TcpService)
    /**加入超时队列-监听指定的设备*/
    fun deviceAcceptTaskInQueue(receive: String, hex: String, client: DeviceConnect, service: TcpService)


    /**对指定设备开启消息监听*/
    fun openDeviceAccept(conn: DeviceConnect)
    /**对指定设备关闭消息监听*/
    fun closeDeviceAccept(conn: DeviceConnect)

    /**是否有设备已经开启消息监听*/
    fun isDeviceAccept(conn: DeviceConnect):Boolean

    /**是否完成*/
    fun isFinish():Boolean
    /**设置完成*/
    fun setFinish()

    /**等待任务完成*/
    fun waitTaskUntilFinish()
    /**添加*/
    fun addTask(run:Runnable)

}

定义一个超时任务队列

abstract class EventTask : EventAction {

    private lateinit var fristClient: DeviceConnect;
    private lateinit var acceptClient: DeviceConnect;
    var isFinished=false;

    private lateinit var acitons: LinkedList<Runnable>

    @Synchronized
    override fun isFinish():Boolean{
        return isFinished
    }

    @Synchronized
    override fun setFinish(){
        try {
            syncTaskLock.lock()
            isFinished=true
            syncTaskCondition.signalAll()
            syncTaskLock.unlock()
        } catch (e: Exception) {
        }

    }


    override fun waitTaskUntilFinish(){
        if(!isFinish()) {
            syncTaskLock.lock()
            syncTaskCondition.await()
            syncTaskLock.unlock()
        }
    }



    val syncTaskLock = ReentrantLock()
    val syncTaskCondition = syncTaskLock.newCondition()

    companion object {
        var exeService: ExecutorService = Executors.newCachedThreadPool()
        var timeOutService: ExecutorService = Executors.newCachedThreadPool()

    }

    /**是否有设备已经开启消息监听*/
    override fun isDeviceAccept(conn: DeviceConnect):Boolean{
       var isAccept:Boolean=false;
       TcpService.instaince.syncExecute {
           isAccept= !(conn.openEnabledReceiverTask.isEmpty())
           TcpService.instaince.synclock.unlock()
       }
        return isAccept;
    }

    override fun openDeviceAccept(conn: DeviceConnect) {
        TcpService.instaince.syncExecute {
            conn.openEnabledReceiverTask.add(this)
        }
    }


    override fun closeDeviceAccept(conn: DeviceConnect) {
        TcpService.instaince.syncExecute {
            conn.openEnabledReceiverTask.clear()
        }
    }

    override fun getFristConnectClient(): DeviceConnect {
        return fristClient
    }
    /**返回待监听的客户端*/
    override fun getAcceptConnectClient(): DeviceConnect?=acceptClient

    abstract override fun receiveProcess(message: String, hex: String, instruct: List<String>): Boolean


    abstract override fun timeOut(): Long


    abstract override fun disposeEvent(message: String, hex: String, instruct: List<String>, client: DeviceConnect, service: TcpService)


    abstract override fun deviceAccept(receive: String, hex: String, client: DeviceConnect, service: TcpService)

    override fun addTask(run: Runnable) {
        syncTaskLock.lock()
        acitons.add(run)
        syncTaskCondition.signalAll()
        syncTaskLock.unlock()
    }



    override fun disposeEventTaskInQueue(message: String, hex: String, instruct: List<String>, client: DeviceConnect, service: TcpService) {
        fristClient=client;
        acitons=LinkedList()
        addTask(Runnable { disposeEvent(message, hex, instruct, client, service)})
        TcpService.instaince.getLogListen()?.received(message,hex,client,this,STATUS_CODE_DISPOSE)
         timeOutService.submit({
            var future = exeService.submit(object : Callable<Boolean> {
                override fun call(): Boolean {
                    while (!isFinish())
                    {
                      while (!acitons.isEmpty())
                      {
                          acitons.pollFirst().run()
                      }

                      waitTaskUntilFinish()

                    }
                    println("执行结束")
                    return true
                }

            })
            timeOut(message,hex,future,client,false);
        })

    }


    private fun timeOut(message: String, hex: String, future: Future<Boolean>, client: DeviceConnect, isReceive: Boolean) {
        var data=DataBean("","","",null);

        try {
            future.get(timeOut(), TimeUnit.MILLISECONDS)
        } catch (e: InterruptedException) {
            e.printStackTrace() //get为一个等待过程,异常中止get会抛出异常
            data.result=ERROR_STATUS
            data.code=ERROR_CODE_INTERRRUPTED;
        } catch (e: ExecutionException) {
            e.printStackTrace() //submit计算出现异常
            data.result=ERROR_STATUS
            data.code=ERROR_CODE_INTERRRUPTED;
        } catch (e: TimeoutException) {
            e.printStackTrace() //超时异常
            data.result=ERROR_STATUS
            data.code= ERROR_CODE_TIME_OUT;
        }
        if(data.code!=null)
        {
            print("给首个连接设备发消息")
            TcpService.instaince.write(getFristConnectClient(),Gson().toJson(data), OutPutSteamMode.DEFAULT)

            if(acceptClient!=null) {
                closeDeviceAccept(acceptClient)
            }
            print("回调结束")
            when(isReceive)
            {
                true-> TcpService.instaince.getLogListen()?.received(message,hex,client,this, TcpService.STATUS_CODE_ACCEPT_BUT_NOT_CALLBACK_DATA)
                else-> TcpService.instaince.getLogListen()?.received(message,hex,client,this, TcpService.STATUS_CODE_DISPOSE_BUT_NOT_CALLBACK_DATA)
            }

        }

    }

    override fun deviceAcceptTaskInQueue(receive: String, hex: String, client: DeviceConnect, service: TcpService) {
        acceptClient=client
        TcpService.instaince.getLogListen()?.received(receive,hex,client,this,STATUS_CODE_DISPOSE)
        addTask(Runnable { deviceAccept(receive, hex, client, service) })
    }

}

 

```java

以上模板思路完成后编写一个心跳事件

class HeartbeatEventTask : EventTask() {

    override  fun receiveProcess(message:String,hex:String,instruct:List<String>):Boolean{
        var pattern = Pattern.compile("[0-9]*");
        return pattern.matcher(message).matches()
    }

    override fun timeOut(): Long = 5000

    
    override fun disposeEvent(message: String, hex: String, instruct: List<String>, client: DeviceConnect, service: TcpService) {
        //默认收到的第一消息是设备的id 并加入到存活的服务器连接列表
        if(client.deviceId==null)
        {
            client.deviceId=message
            service.saveSocketConnectMap(message,client)
        }
        TcpService.instaince.write(client,message, OutPutSteamMode.DEFAULT)
        setFinish()
        
    }
    override fun deviceAccept(receive: String, hex: String, client: DeviceConnect, service: TcpService) {

    }

}

 

编写一个对设备控制的指令

/**
 * Created by linxingzhu on 2018/7/10.
 */
class SendDeviceEventTask : EventTask() {

    /**
     * php-> Device 2 "22" false
     * */
    override fun receiveProcess(message: String, hex: String, instruct: List<String>): Boolean {
        val b= instruct.size >= 4
                && "\$php->".equals(instruct[0])
                && "Device".equals(instruct[1])
                && Pattern.compile("[0-9]*").matcher(instruct[2]).matches();
        return b;
    }

    override fun regx():String="[\"]+.+[\"]+|[^\\s]+[ ]*+"


    override fun timeOut(): Long = 5000

    private val timeinterval = 1000L;


    private val CODE_SUSSCESS = 0
    //1表示参数错误
    private val ERROR_CODE_PARAMETER = 1
    //2表示像连接成功但写入数据失败
    private val ERROR_CODE_WRITE = 2
    //3表示锁控板未连接到服务器
    private val ERROR_CODE_NO_CONNECT = 3


    override fun disposeEvent(message: String, hex: String, instruct: List<String>, client: DeviceConnect, service: TcpService) {
        /** 将数据提交到队列*/
        val deviceId = instruct[2]
        var message = instruct[3]
        if(message.indexOf("\"")==0&&message.lastIndexOf("\"")==message.length-1)
        {
            message=message.substring(1,message.length-1)
            println(message)
        }

        var isHex=false
        if(instruct.size==4)
        {
            isHex=false;
        }else
        {
            isHex = java.lang.Boolean.valueOf(instruct[4])
        }
        var connect = service.connectDeviceMap[deviceId]
        when (true) {
            connect == null -> {
                callBackData(client, "error code:${ERROR_CODE_NO_CONNECT}")
            }
            (connect?.socket?.isConnected)==false->{
                callBackData(client, "error code:${ERROR_CODE_NO_CONNECT}")
            }
            else -> {
                try {
                    TcpService.instaince.write(connect!!,message,if(isHex) OutPutSteamMode.HEX else OutPutSteamMode.DEFAULT )
                    callBackData(client, "error code:${CODE_SUSSCESS}")
                } catch (e: Exception) {
                    callBackData(client, "error code:${ERROR_CODE_WRITE}")
                }

            }
        }
    }
    fun callBackData(client: DeviceConnect, content:String) {
        TcpService.instaince.write(client,content, OutPutSteamMode.DEFAULT)
        setFinish()
    }

    override fun deviceAccept(receive: String, hex: String, client: DeviceConnect, service: TcpService) {

    }



}

 

编写一个设备发出指令并等待设备回传事件

class ReceiveDeviceEventTask : EventTask() {

    /**
     * php-> Receive 2 "22" false
     * */
    override fun receiveProcess(message: String, hex: String, instruct: List<String>): Boolean {
        return  instruct.size >= 4
                && "\$php->".equals(instruct[0])
                && "Receive".equals(instruct[1])
                && Pattern.compile("[0-9]*").matcher(instruct[2]).matches();
    }

    override fun regx():String="[\"]+.+[\"]+|[^\\s]+[ ]*+"


    override fun timeOut(): Long = 5000

    private val timeinterval = 1000L;


    private val CODE_SUSSCESS = 0
    //1表示参数错误
    private val ERROR_CODE_PARAMETER = 1
    //2表示像连接成功但写入数据失败
    private val ERROR_CODE_WRITE = 2
    //3表示锁控板未连接到服务器
    private val ERROR_CODE_NO_CONNECT = 3


    override fun disposeEvent(message: String, hex: String, instruct: List<String>, client: DeviceConnect, service: TcpService) {
        /** 将数据提交到队列*/
        val deviceId = instruct[2]
        var message = instruct[3]
        if(message.indexOf("\"")==0&&message.lastIndexOf("\"")==message.length-1)
        {
            message=message.substring(1,message.length-1)
            println(message)
        }

        var isHex=false
        if(instruct.size==4)
        {
            isHex=false;
        }else
        {
            isHex = java.lang.Boolean.valueOf(instruct[4])
        }
        var connect = service.connectDeviceMap[deviceId]
        when (true) {
            connect == null -> {
                callBackData(client, "error code:${ERROR_CODE_NO_CONNECT}")
            }
            (connect?.socket?.isConnected)==false->{
                callBackData(client, "error code:${ERROR_CODE_NO_CONNECT}")
            }
            else -> {
                //如果当前有监听等待
                while (isDeviceAccept(connect!!))
                {
                    Thread.sleep(200)
                }
                //对设备开启监听、
                openDeviceAccept(connect!!)

                try {
                    TcpService.instaince.write(connect!!,message,if(isHex) OutPutSteamMode.HEX else OutPutSteamMode.DEFAULT )

                } catch (e: Exception) {
                    callBackData(client, "error code:${ERROR_CODE_WRITE}")
                }

            }
        }
    }
    fun callBackData(client: DeviceConnect, content:String) {
        TcpService.instaince.write(client,content, OutPutSteamMode.DEFAULT)
        setFinish()
    }

    override fun deviceAccept(receive: String, hex: String, client: DeviceConnect, service: TcpService) {
        //如果为非数字
        if(!Pattern.compile("[0-9]*").matcher(receive).matches()) {
            TcpService.instaince.write(getFristConnectClient(),receive,OutPutSteamMode.DEFAULT )
            setFinish()
        }

    }
}

 

资源下载 1-客户端UI下载 2-服务器UI下载   3-代码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值