信息系统实践手记8-两模块通讯的一些事

说明:信息系统实践手记系列是系笔者在平时研发中先后遇到的大小的问题,也许朴实和细微,但往往却是经常遇到的问题。笔者对其中比较典型的加以收集,描述,归纳和分享。

摘要:此文描述了笔者接触过的部分信息系统或平台之间的对接构型和情况,挂一漏万的总结分享之。

正文

系列随笔目录:信息系统实践手记 (http://www.cnblogs.com/taichu/p/5305603.html

作者:太初

转载说明:请指明原作者,连接,及出处。

正文

在信息系统开发和对接的过程中,免不了要遇到两个模块之间的消息互通,自家开发的2个模块互通,或者自己模块和第三方某个模块通讯。

这里尽量不涉及具体技术(这个大家自己找资料看书),主要是掰扯一下会涉及到的一些思考和情况。

1.对接协议的2个层次

两个代码实体(简称模块)互相需要通讯,往往在不同的主机(PC/IP)上,也偶有在同一个主机上的,TCP/IP协议已经屏蔽了物理机的差异,通过IP/PORT来区分资源,区分模块或功能对等实体。回过来,2个模块要通讯,2端代码要交互信息(数据/消息/信令/码流/结构/随你怎么称呼),参照目前互联网的TCP/IP协议或其他奇怪协议,基本分为两种层次:

A:物理实现层(对于TCP/IP中的物理层,链路层等)的比特流,二进制,高低电平,网卡,网络设备等支持这个协议。比如3伏特/12伏特表示0或1等等,这是电气特性;可靠性依赖于硬件的工作特性,电气特性,以及纠错手段(一些数学方法)。

B:高层(统一叫高层,就是这个意思),基于二进制bit层次上的有含义的层次,字节流层次,byte(一般是8bit=1byte),而byte就对应了byte编码规范,比如ASCII或UTF-8,这样一串bytes就有逻辑含义了(26个英文字母及大小写,自然数10个数字,特殊符号,回车换行,加减乘除符号,不可见符号等等);其实网络上传递的都是字节流,而TCP/IP协议主要也是处理这个字节流从端到端的传送;可靠性依赖于下层A的bit流,并也可以增加适当的校验CRC等各种手段(也是一些数学方法)

所以虽然ISO/OSI的7层网络模型设计的很好,其实落实到实际实现的TCP/IP协议,也就主要分为以上A/B两个层次,A中还细分几个,B中也有细分但用的不多;主要理解这2个层次,从物理bit的可靠传输,架构其有逻辑含义的高层字节byte传输,这么个概念。后续主要就谈B层了,毕竟A层次目前已经稳定,除非量子力学颠覆当前的计算机原型(节点PC),然后自然而然的可能颠覆网络基础物理层A的电气特性,搞些先进的,这个我们就不谈了,还有5到10年就扑面而来了。

这里只谈B层;

2.TCP/IP协议主要分为TCP/UDP2种

TCP/IP协议分为主要的2种,UDP/TCP:

(1)TCP:面向连接(在网络基础层A上维护的逻辑上的连接通道) 的有状态的字节流通讯,保证数据包的按序及正确传送,有状态,所以能错误重传,并维护连接通道;但数据报的缓存及发送依赖于“逻辑连接通道”两端模块程序(往往是OS的网络驱动,网卡的驱动程序等)自主决定。所以会产生粘包及粘包如何分割的问题,这是TCP经典问题,请另查资料(或看netty官网的userguide入门章节,有比较简单经典的描述);

场景:需要可靠连接,直接拿来用的场景,牺牲一定的效率;用的较广泛;

(2)UDP:无连接,不保证数据包按照发送顺序到达目的地,甚至不保证能到达目的地;它其实允许2端模块自己通过高层协议来组织,数据包的顺序检查,丢包重传,及状态流转等;等于自己实现一个小小的简单TCP;

场景: 网络环境表稳定可靠,对数据正确性及顺序无特别严格要求,效率较高;比如局域网播放视频等;

(说明:随着网络硬件性能,模块所在节点PC或服务器的性能提升,也许大家觉得即使看视频也用TCP来的更方便和效果好,那也是可以的,这无一个定论,看具体情况和项目方案的需求和实施情况而定)

3.针对TCP的几种使用方法

TCP比较好用,但是有个特点就是粘包。虽然它是面向连接,有状态维护管理,丢包重传,且保证次序。但是两端节点上的庄模块的网络驱动底层库,各自的算法,缓存cache和策略,效率,切分包的大小(MTU)等都不同,导致接收方得到的包只在整体字节流bytes上是一致的,但无法知道发送方每次send给底层的byte字节是如何划分的。这就是经典的粘包及切分问题;一般有如下几个方法来处理;

(a)方法1:定长字段法;

  这样就不怕粘包了,发送端只管发,接收端从接受缓存不断轮询,如果满了一定长度length后,就读入;这里当然假设TCP是有序,丢包会重传的。

  优点:实现简单;逻辑也简单;

  缺点:一旦TCP传输有错(网络不好,概率偶发,协议栈缺陷等,总会错误),则整体就会偏移,数据错位就会错误;

  优化:根据其缺点,可在定长中增加特殊头标记,比如定长length=64bytes,其中开始标记flag=\x0C等,当满足两者,就解码为逻辑内容,内容正确就用,内容错误就丢弃,并找到下一个有效的定长数据片(且以flag开头);这其实已经有一点TLV的雏形了。

(b)方法2:分隔符方式(变长字段法);

  和定长字段法相对的,就是通过一个分隔符来区分前后两端内容,则没断长度可变化,分隔符不可重复,同样能解决粘包问题;

  有点:实现简单,逻辑较简单,比较可靠;

  缺点:要保证分隔符是payload(有效载荷,即实际负载和传输的数据)中不能包含的!而且算法效率低下,需要每个byte都检查是否为分隔符;

  优化:如果能配合定长的数据片,那其实等价于加一个flag头。

(C)方法3:TLV方式(经典高效):

  TLV是比较经典的方式,用的相对较多。TLV(一般指Type-Length-Value)。它的协议一般会约定一个head头结构,包含flag和length,flag用来找到TLV的头(是个标记字节,不必唯一,但不能很多),找到flag后,就根据协议约定解析head头结构,解析失败则继续查找flag;解析成功后,就能获得head+body的整体长度length,从而解析得到body的数据;在body中通过一组组不定长的(length-value)结构,一个长度一个value值来承载payload,但length字段的自身长度是固定的,一般为1都4个字节之间,看TLV整体的协议定义;body的length和head的中length的自身长度也不必要一定一致。另外,这个type是类型的含义,是TLV协议手册的约定,一般会说明有K组<length,value>,每组是int,long,double,bytes[],等等;

  优点:高效的通过length字段获取value,不用每个字节都检查;且支持不同的数据结构;

  缺点:实现比较复杂,两边TLV协议手册显然比前2种方法的描述要详细;

  改进:可以通过诸如JAVA的反射或其他方法,来将TLV协议通过“配置文件”的方式,让程序自动根据清晰明了容易维护的配置文件来生成编解码程序(CODEC)。

4.针对TCP心跳的一些说明

TCP协议内容较多,有好几本大书,但核心内容,网上也转载很多,这里只提一些内容。

TCP如果不在初始化socket的时候给予超时timeout设定(看tcp类库支持哪些超时,一般如java io/NIO支持连接超时,传输超时等),那么默认就是2小时(120分钟),在120分钟内TCP协议内部自己有心跳维持socket连接通道,超过120分钟,则按照状态机变化,两端都开始拆除TCP连接。当然,两端庄模块开发的如果不好,这就会导致对端有大量端口TIME_WAIT等等TCP状态机不能顺利,快速,高效的拆除并被复用,导致资源消耗,甚至耗光65535个port口。

除了TCP自身的超时,或者网络lib库能力范围内给予的连接超时,传输超时(闲置idle超时)外,桩模块可以人为的在逻辑层添加自己的超时和心跳机制。举例如下:

(1)收到PING,就发PONG,收到PONG,不响应;这是对等心跳探测包,有发起者探测对方是否活着alive;

(2)两边约定心跳间隔时间,比如每120秒发送心跳包(比如“HB”2个字符,或某种字节等),或者约定只有server发给client,不用反向;

特别说明:这是高层逻辑的心跳,应用层自己使用的,而且其实现根据前述3种使用方法而不同,比如你用TLV,那么也需要额外定义一个“心跳包”的协议;

5.用哪些类库?

一般开发桩模块的时候,两端约定好传输协议,比如TLV,那么就各自开发。你用熟悉的语言比如java,而且会进一步使用现成的框架,比如netty(异步io框架),这样你就不用赤裸的使用java的nio自己一步步处理,不用重复发明轮子。netty是一个非常好用的库,开发者同时也开发了mina,两个库有点类似,各有千秋和侧重。详见我整理的[ITIS-资料集合贴]中的介绍和电子书;

6.对接协议的的安全性问题

TCP是有连接,有状态,有序,丢包重传的,所以他有基础的正确性保证。但TCP完全会受到重传攻击,或侦听窃听,或篡改数据包等破坏方式。而且TCP保证的是网络层的字节流的按序正确到达,不保证上层逻辑(应用层)认为的数据是百分百正确的。所以,有如下建议:

(1)可以根据需求,对自己的数据进行编码,压缩,加密;

(2)可以参考一些开源的密钥,加密算法,认证,证书等协议的使用;

(3)曾经这样弄过,给payload转为base64,并且做了MD5摘要,传到对端MD5用来验证数据对不对,也可作为异步反馈的key值。

总结,总是TCP协议丰富多彩,核心内容也就这些,如果熟悉一些框架和常用手段,再加上一些诸如MD5,加密压缩算法等,完全可以自己搭建和实现不同的传输协议,满足不同情况的要求,在两个对端桩模块之间实现数据的传递。

END

时间: 2024-10-28 20:16:14

信息系统实践手记8-两模块通讯的一些事的相关文章

信息系统实践手记4-平台对接的一些思考

说明:信息系统实践手记系列是系笔者在平时研发中先后遇到的大小的问题,也许朴实和细微,但往往却是经常遇到的问题.笔者对其中比较典型的加以收集,描述,归纳和分享. 摘要:此文描述了笔者接触过的部分信息系统或平台之间的对接构型和情况,挂一漏万的总结分享之. 正文 系列随笔目录:信息系统实践手记 (http://www.cnblogs.com/taichu/p/5305603.html) 作者:太初 转载说明:请指明原作者,连接,及出处. 1.什么是平台对接? 一般的信息系统有两种:一种是单套单功能的,

信息系统实践手记7-对接卡口平台细节

说明:信息系统实践手记系列是系笔者在平时研发中先后遇到的大小的问题,也许朴实和细微,但往往却是经常遇到的问题.笔者对其中比较典型的加以收集,描述,归纳和分享. 摘要:此文描述了笔者接触过的部分信息系统或平台之间的对接构型和情况,挂一漏万的总结分享之. 正文 系列随笔目录:信息系统实践手记 (http://www.cnblogs.com/taichu/p/5305603.html) 作者:太初 转载说明:请指明原作者,连接,及出处. 正文 在围绕地图(GIS)展开的应用中,需要接入很多第三方的平台

信息系统实践手记5-CACHE设计一例

说明:信息系统实践手记系列是系笔者在平时研发中先后遇到的大小的问题,也许朴实和细微,但往往却是经常遇到的问题.笔者对其中比较典型的加以收集,描述,归纳和分享. 摘要:此文描述了笔者接触过的部分信息系统或平台之间的对接构型和情况,挂一漏万的总结分享之. 正文 系列随笔目录:信息系统实践手记 (http://www.cnblogs.com/taichu/p/5305603.html) 作者:太初 转载说明:请指明原作者,连接,及出处. 1.CACHE是啥? 最近一直在弄scala,Spark,Pyt

信息系统实践手记3-按业务展开的代码剥离

说明:信息系统实践手记系列是系笔者在平时研发中先后遇到的大小的问题,也许朴实和细微,但往往却是经常遇到的问题.笔者对其中比较典型的加以收集,描述,归纳和分享. 摘要:介绍一下业务相关的代码优化(比较抽象,偏系统分析和设计). 正文 1.问题出现 如前面2次手记()提到的这个客户端,毛病不少,要开发的面面俱到,毫无瑕疵,难而又难.这次我们又遇到了其实可以泛泛的归为“面向方面的编程”的问题. [END]

信息系统实践手记6-JS调用Flex的性能问题一例

说明:信息系统实践手记系列是系笔者在平时研发中先后遇到的大小的问题,也许朴实和细微,但往往却是经常遇到的问题.笔者对其中比较典型的加以收集,描述,归纳和分享. 摘要:此文描述了笔者接触过的部分信息系统或平台之间的对接构型和情况,挂一漏万的总结分享之. 正文 系列随笔目录:信息系统实践手记 (http://www.cnblogs.com/taichu/p/5305603.html) 作者:太初 转载说明:请指明原作者,连接,及出处. 正文 在笔者实践中,越到有些情况下(比如开发GIS地图应用),客

python threading模块使用 以及python多线程操作的实践(使用Queue队列模块)

今天花了近乎一天的时间研究python关于多线程的问题,查看了大量源码 自己也实践了一个生产消费者模型,所以把一天的收获总结一下. 由于GIL(Global Interpreter Lock)锁的关系,纯的python代码处理一般逻辑的确无法活动性能上的极大提升,但是在处理需要等待外部资源返回或多用户的应用程序中,多线程仍然可以作为一个比较好的工具来进行使用. python提供了两个模块thread和threading 来支持python的多线程操作.通俗的讲一般现在我们只使用threading

Android OTG之USB转串口模块通讯

微信公众号:CodingAndroid CSDN:http://blog.csdn.net/xinpengfei521 1.背景简介 我们公司开发了一款室内机平板APP应用,要求平板能去控制智能门锁.等其他智能设备,智能门锁不是我们公司开发的,与我们公司属于合作关系. 2.分析及实现思路 智能门锁的控制是通过使用 433射频(不了解的请百度)来进行通讯的: 平板是没法与智能门锁直接进行通讯,但是厂家提供了一个433通讯模块(支持串口): 而平板(支持OTG)是支持USB转串口模块的,所以整个流程

WebRTC手记之WebRtcVideoEngine2模块

转自:http://www.cnblogs.com/fangkm/p/4401143.html 终于讲到视频数据的编码发送模块了,不容易.总体来说也看了不少时间WebRTC的源码了,最大的感触就是各个模块在开发的时候非常独立,每个模块都定义了自己的一套接口,最后串起来的时候添加各种适配对象来转接.这给我们这些刚开始源码阅读的人带来非常大的苦恼,不过WebRTC的模块内的结构设计还是很不错的,不然我也没有看下去的动力. 注意命名,WebRtcVideoEngine2带了个2字,不用想,这肯定是个升

YII 两表间和两模块间的数据库查询

这段时间在学YII,虽然Yii做网页挺方便,它的作用也不止这么简单,但对于刚弄的新手来说,要弄会它实在太难,想完成某个功能光想找文档就能让你"疯狂",,,好,废话不多说,下面讲下标题要实现的两个功能:(PS:不知是不是太简单而没人看得起还是怎么,想要实现在网上找文档找到吐都没找到..)我新建了post模块和group模块,有3张表(都在同一个数据库的),post表和posttype表放在post模块里,group表放在group模块里. 好,首先,实现post去查询postType里的