通道服务名:tcp-client
工程名称:fox-edge-server-channel-tcp-client
说明:
tcp-client 通道服务,用于支持现场设备作为tcp-server通信的场景。
在现实项目中,有很多设备是基于TCP进行通信的,此时这些设备作为TCP的服务端,接受来自上位机的TCP连接。
当连接建立后,主要有两种通信模式,一种是主从半双工,一种是全双工方式
主从半双工 ,就是上位机主动对这些TCP设备发起连接后,上位机和设备之间,严格遵循一问一答的方式。 它们之间的一问一答,可以通过时序上的先后顺序,就能简单的判定。
全双工方式 ,就是上位机主动对这些TCP设备发起连接后,上位机和设备之间,并不遵循通过时序的问答来进行交互。 它们之间,完全是双向互相对等通信,各问各的,各答各的。它们并不存在先后关系,所以它们的互相操作,要靠彼此约 定的通信格式,以及通信内容来彼此识别。
针对这个业务场景,灵狐开发了 tcp-client 这种通道服务,来支持这两种场景。
进一步考虑到用户的现场设备可能有很多种类型,所以 tcp-client 支持为每一个通道,定义采用何种通信方式。
TCP是面向流的传输协议,但是上位机与设备的之间的交互,是一种彼此会话的动作。 此时会出现一种对应的现象,必然会出现一种所谓的 粘包 的现象。
所谓 粘包 ,设备向上位机发送了两组报文,结果上位机收到的是一组报文,而这组报文内容是两个组报文粘合在一起的内容。
例如:
设备->上位机:
AA AA 03 BB BB BB
AA AA 04 DD DD DD DD
结果上位机收到的是:
AA AA 03 BB BB BB AA AA 04 DD DD DD DD
为了解决这个问题,设备厂商约定,它们的报文是【AA AA】 + 【长度】+【数据】的格式,上位机收到一组粘包的数据后, 按这个格式进行拆解,就能够得到这真正的两组报文。
使用TCP协议传输数据的设备制造厂商,它们的设备协议上,都会定义有报头和报长两种信息,来帮助分包。
如果它们的设备没有这种报头和报长两这两个关键信息,别白费力气了,赶紧找设备厂商解决,或者直接更换设备厂商。
设备制造厂商在设计它们的通信协议的时候,会有两种模式,一个是全双工模式,一种是半双工模式。
提醒:不会有哪混合两种的通信方式。如果说有,把你开发中遇到交互方面的时序问题,留给他去回答。
就是上位机主动对这些TCP设备发起连接后,上位机和设备之间,严格遵循一问一答的方式。
它们之间的一问一答,可以通过时序上的先后顺序,就能简单的判定。
在此种模式下,设备的身份可以通过设备的 IP:PORT 来进行身份识别。
该模式只支持 execute 操作。
就是上位机主动对这些TCP设备发起连接后,上位机和设备之间,并不遵循通过时序的问答来进行交互。
它们之间,完全是双向互相对等通信,各问各的,各答各的。它们的应答并不存在先后关系,所以它们的互相操作, 要靠彼此约定的通信格式,以及通信内容来彼此识别。
最常见的方式,有协议报文自带 身份特征 信息和 交互序号 ,通过这个特征,你就能知道回答你的设备 是具体的那一台设备,跟你进行问答的是哪一个问答。
注意:在这种模式下,需要使用到开发对应的JAR解码器,来帮助报文内容的识别。
该模式只支持 publish 和 report 操作。
提供了加载解码器JAR的方式,来对报文的粘合包进行自动化拆包,对报文的碎包进行自动化的组包。
同样解码器JAR,也能对全双工方式下的身份识别特征进行内容识别。
粘包/拆包的范例,开发者可以参考
tcp-client 通道服务的包括全局配置和通道配置
jarFile:解码器文件
logger:是否打印后台日志
{
"logger": false,
"decoderList": [
{
"jarFile": "/jar/decoder/fox-edge-server-protocol-zktl-air6in1.v1.jar"
},
{
"jarFile": "/jar/decoder/fox-edge-server-protocol-core.v1.jar"
},
{
"jarFile": "/jar/decoder/fox-edge-server-protocol-zktl-air6in1.v1.jar"
},
{
"jarFile": "/jar/decoder/fox-edge-server-protocol-zktl-air5in1.v1.jar"
}
]
}
host:设备IP
port:设备端口
mode:工作模式 full-duplex 或者 half-duplex
handler:进行报文拆解的解码器的JAVA代码,这个有具体某款设备的解码器信息,该信息有设备通信协议解码器的开发者 写的代码决定,该信息的填写方式由他提供。比如下文是air6in1开发者所提供的填写内容。
{
"host": "127.0.0.1",
"mode": "full-duplex",
"port": 502,
"handler": {
"splitMessageHandler": "cn.foxtech.device.protocol.v1.zktl.air6in1.handler.ZktlSplitMessageHandler"
}
}
如果是全双工模式(包括设备主动上报的工作模式),需要写解码器,此时需要看这段内容。
下面的内容,都是跟全双工方式相关的,如果你的是半双工方式设备,可以跳过这一节内容。
全双工模式下的操作方法,只有单工的publish和report两种模式,没有主从半双工的execute模式。
这样设计的目的,是因为execute只适合一问一答式的传统自动化设备。
但是,对于很多会采用TCP的设备来说,它们的设计更多的是采用全双工的方式。
换句话说,在传输层面,上行和下行是彼此独立的,上行和下行,可以认为是两条各自独立的单向通道。
所以,tcp-server的操作方法,也跟着用publish和report来分别对应上行和下行数据的传输。
TCP 是面向流的传输协议,想要在上面传输会话动作,必然会出现所谓的粘包问题。
所以,设备制造厂商,它们的设备协议上,会定义有报头和报长两种信息,来帮助分包。
如果它们的设备没有这种报头和报长两这两个关键信息,别白费力气了,赶紧找设备厂商解决,或者直接更换设备厂商。
以下以中科图灵的设备协议为范例:
某公司的安防设备,它的通信报文格式为
报头:4 字符, ‘2’ ’4’ ’2’ ’4’;
通信类型:1 字符
设备类型:1 字符
长度:2 字符
数据区:N字符
包尾:2 字符,’A’’ A’
报文范例:
2424 08 43 867572058700527 89861121245014174191 0058009b00b3006400b6019e110200 aa
2424是固定的报头,28是报长,这个适合就可以通过 这两个信息,对粘合成一长串的报文,进行准确的断句。
tcp-server提供了自动拆包的接口:cn.foxtech.device.protocol.v1.utils.netty.SplitMessageHandler
开发者应该写一个解码器,并派生一个子类,为tcp-server指出报头和报长的特征,那么tcp-server在接收到数据流之后,
会使用SplitMessageHandler的派生类自动进行拆包操作。
你可以通过TCP工具给它发送测试字符串的报文进行效果测试:
24240843867572058700527898611212450141741910058009b00b3006400b6019e110200aa
设备层面的解码器会收到这个主动上报的报文。
tcp-client 启动的时候,会自动创建一个默认的全局配置
{
"decoderList": [{
"decoder": [{
"jarFile": "\\jar\\decoder\\fox-edge-server-protocol-zktl-air6in1-1.0.2.jar"
}],
"keyHandler": "cn.foxtech.device.protocol.v1.zktl.air6in1.handler.ZktlServiceKeyHandler",
"serverPort": 9301,
"splitHandler": "cn.foxtech.device.protocol.v1.zktl.air6in1.handler.ZktlSplitMessageHandler"
}, {
"decoder": [{
"jarFile": "\\jar\\decoder\\fox-edge-server-protocol-zktl-air5in1-1.0.2.jar"
}],
"keyHandler": "cn.foxtech.device.protocol.v1.zktl.air5in1.handler.ZktlServiceKeyHandler",
"serverPort": 9302,
"splitHandler": "cn.foxtech.device.protocol.v1.zktl.air5in1.handler.ZktlSplitMessageHandler"
}]
}
用户在通道界面创建一个tcp-server类型的通道之后,在通道上配置好身份特征特征,那么Fox-Edge就会遵循下列操作流程
【现场设备】《==TCP==》【通道服务】(tcp连接-身份特征-通道名)《==Channel==》【设备服务】
这样,上层应用就能够以channel的方式,进行跟远程的现场设备,基于tcp的方式进行交互操作了。
{
"host": "127.0.0.1",
"mode": "full-duplex",
"port": 502,
"handler": {
"splitMessageHandler": "cn.foxtech.device.protocol.v1.zktl.air6in1.handler.ZktlSplitMessageHandler"
}
}
设备主动上报模式下,向等待设备主动发送一次身份特征报文后,此时才完整真正的设备身份认证。
然后,才能进行向设备主动执行 publish 操作