一场关于异构平台通信的风波(粘包·大小端方式·网络字节序)

一.引子

前段时间用StriveEngine做一个信息采集系统,服务器是Windows的,客户端是各种单片机,以及Unix等等平台。这些异构的平台,被我召集起来“加强对话, 扩大共识, 深化合作”。都说有人的地方就有江湖,讲真,机器世界也一样!这些异构的平台,平日里各自为政,井水不犯河水,倒也相安无事。如今群雄会盟,共商大计,如我所料,势必会上演一波真正的血雨腥风!

就像新闻联播里常说的,“加强对话, 扩大共识, 深化合作”,首先得“加强对话”吧。

看着各位爷陆续到场,我稍稍清了清嗓子,不揣冒昧,说道:

“各路英雄好汉,这次把大家召集前来,是想让大家强强联手,搞一个大新闻!”

场下变得安静,各个聚精会神。于是我继续说道:

“到底是搞个什么呢?就是搞一个【信息采集系统】!”

场下开始窃窃私语。我接着说:

“大家有什么好的建议,有什么需要彼此沟通了解的,都请各抒己见,畅所欲言!”

掌声响起。

掌声落定。

代表们开始争相发言。

于是问题来了——他们都不讲普通话的好吗!——某型号单片机操一口湖南话,Windows服务器则操一口纽约腔——场面瞬时凌乱!更有一不可名状某终端,恕我孤陋寡闻,您讲的是......是爪哇话吗?怎么还一股孜然味儿?更有两位爷看上去是一言不合,准备动手!我还在纳闷,这两位语言都不通,是怎么一言不合的?!······场面逐渐失控,已容不得我多想!我大喝一声!30名侍卫持枪从侧门进场列阵台前,全场寂静!接着我一个响指,殿外快马加鞭,送上一红绸遮盖的大匾,全场注视。我手气绸落,鎏金大匾上赫然写着金闪闪明晃晃的几个大字:

二.面向字节流的TCP通信

这一切还得从TCP通信说起。

TCP大家都不陌生,是网络协议栈中最重要的协议之一。StriveEngine通信引擎既支持TCP也支持UDP,我们根据业务场景的需要选择的是TCP。TCP是面向字节流的。

      

三.面向字节流通信所引发的问题

正是因为TCP通信面向字节流,同时也引发也一系列相关问题需要我们去着手解决。

1.粘包

其中首当其冲的,也是大家最熟悉的就是粘包问题。

字节流就跟水流一样,当两个消息一起读取时,你无法分别出二者的边界。

2.字节序·大小端方式

TCP是面向字节流的,这个字节流本质上来说就是内存片段。那么问题来了,发送主机与接收主机的存储方式可能不一样,也就是主机字节序不一致。

打个简单的比方吧,以前中国的书都是从右往左读写的,而现在都是从左往右读写的。假使现代人按照现在的习惯去读过去的书,就会因为【主机字节序】不一致而出现问题。

就如同读写可以从左往右,也可以从右往左,马路可以规定靠左侧行驶也可以规定靠右侧行驶——存储方式也有两种——【大端方式】和【小端方式】。

《格列佛游记》中记载小人国中形成了两派政治势力,一派主张吃鸡蛋时要从大端开始剥,另一方则主张要从小端开始剥,一言不合就兵连祸结,烽火频年。

计算机科学借用了这个典故来命名两种存储方式:

遗憾的是大小端方式的分歧在计算机世界里也未能达成一致,因此就造成了异构平台通信过程中主机字节序列不一致的问题。

四.如何解决?

首先要明确一点,这些问题都是【应用层】的问题!因为传输层,或者整个底层通信所肩负的职责就是【通信】,其他的事情不该管也管不了!特别是TCP通信,我们知道TCP是可靠传输——发送方发的啥我保证原封不动的给你送到,至于你收到一看,哎呀,包粘在一起了我怎么分得清楚?哎呀,这发过来的数据我解析出来怎么是乱码?——这都不关TCP通信的事!这是你程序员要做的消息处理的工作,消息传输TCP帮你干了,而且TCP是出了名的"铁齿金不换,诚实可靠小郎君",已经仁至义尽,处理消息、解析消息的工作就要靠身为程序员的你来大显身手了!

1.粘包问题

StriveEngine通信引擎提供了两种解决方案:

文本协议模式

   二进制协议模式

其中更为根本的是二进制协议模式。二进制协议通过给消息加上报头,从而为消息定界。



    // 摘要:
    //     二进制协议助手接口。
    public interface IStreamContractHelper
    {
        // 摘要:
        //     消息头的长度。
        int MessageHeaderLength { get; }

        // 摘要:
        //     从消息头中解析出消息体的长度(注意,不是整个消息的长度,而是不包含消息头的Body的长度)。
        //
        // 参数:
        //   head:
        //     完整的消息头,长度固定为MessageHeaderLength
        int ParseMessageBodyLength(byte[] head);
    }

这个接口是需自己来实现的。接口只要求了两件事:1.消息头长度是多少?2.如何从消息头中取出消息体长度,从而间接取出消息体。至于具体的协议如何设计,这个并没有一定之规。

2.字节序问题

字节序的问题就更简单了。已经说过,通信负责把数据原封不动的从端到端进行传递,现在数据交给我了,我发现字节序不一致。不一致怎么办?转换呗!

 void tcpPassiveEngine_MessageReceived(IPEndPoint serverIPE, byte[] bMsg)
 {
     ······
 }

这个字节数组就是收到的数据,该怎么转换在方法体里面做就是了。而且这些转换都早已被封装成API,因此并没有什么难度,本文就不赘述了 。

———————————————附项目源码下载地址———————————————————

五.言归正传

为川者决之使导 ,为民者宣之使言。从那以后,那些机器之间的交流日益加深,有些还建立了深厚的友谊。我时常训导他们,你们虽然是机器,但是也要有人味,要放下那些所谓的成见,求同存异。大家的思维方式、文化背景、受教育程度也许都不尽相同,但是只要大家以一颗开放的心去彼此了解,彼此沟通,交换立场,推己及人,就能开展合作,就能超拔出个人的小生命,而进入到一个更大的生命中。要完成一个数据采集系统,你们其中的任何一个都不能单独胜任,只有靠大家群策群力。而要做到群策群力,就要兼收并蓄,不能各执一端。比如你是小端方式存储,就非要排斥搞大端方式的,视他们为异端,恨不得消灭殆尽,这是最危险的!一定要相互理解相互包容,要尝试去了解对方,学习对方的话语。还有些高级些的系统瞧不起单片机,觉得跟他们没有共同语言,这也是不对的。尺有所长寸有所短,要优势互补才对。管子讲:“和合故能习,习故能偕,偕习以悉,莫之能伤也”,只有和合偕习,才能真正强大!

后来陆续有机器私信给我,说学到了很多做人的道理。为此我倍感欣慰。

时间: 2024-10-12 13:56:38

一场关于异构平台通信的风波(粘包·大小端方式·网络字节序)的相关文章

请讲普通话——一场关于异构平台通信的风波(粘包·大小端方式·网络字节序)

一.引子 前段时间用StriveEngine做一个信息采集系统,服务器是Windows的,客户端是各种单片机,以及Unix等等平台.这些异构的平台,被我召集起来“加强对话, 扩大共识, 深化合作”.都说有人的地方就有江湖,讲真,机器世界也一样!这些异构的平台,平日里各自为政,井水不犯河水,倒也相安无事.如今群雄会盟,共商大计,如我所料,势必会上演一波真正的血雨腥风! 就像新闻联播里常说的,“加强对话, 扩大共识, 深化合作”,首先得“加强对话”吧. 看着各位爷陆续到场,我稍稍清了清嗓子,不揣冒昧

Python入门学习-DAY32-链接循环与通信循环,粘包问题,远程控制,文件上传与下载

链接循环与通信循环 服务端 from socket import * IP = '127.0.0.1' PORT = 8181 ADDRESS = (IP, PORT) BUFSIZE = 1024 server = socket(AF_INET, SOCK_STREAM) server.bind(ADDRESS) server.listen(5) tag=True while tag: conn, addr = server.accept() while tag: try: data = co

Oracle Study之案例--异构平台传输表空间(Linux至AIX)

Oracle Study之案例--异构平台传输表空间(Linux至AIX) 系统架构: 可                   源    库               目标库 操作系统 Linux RH6    AIX 5.3-09 主机名 rh6(192.168.8.245) aix211(192.168.8.211) 数据版本 Oracle 11gR2 Oracle 11gR2 数据库名 prod orcl 表空间 test1 test1    可传输表空间概述 Oracle 的可传输表空

动手打造自己的跨语言异构模块通信解决方案

目前主流的跨语言异构模块通信方案有很多种,比如: 1.跨语言的RPC调用(Apache Thrift):它是Facebook贡献给Apache基金会的开源项目,旨在构建跨语言平台的通信方案.目前它支持非常多种语言,其中当然包括C/C++和Java.Thrift内置一个语言编译器,可以根据Thrift的语法规范,编译生成指定语言的RPC调用模块,功能也是非常的强大.Thrift的语法规范里面定义了数据类型.数据模块结构,有点类似WebService里面的WSDL文件.通过Thrift,我们就可以实

异构平台同步(Mysql到Oracle)

Oracle GoldenGate学习之--异构平台同步(MySQL到Oracle) 如图所示:源端采用Mysql库,目标端采用Oracle库 一.OGG安装配置(源端) 1.OGG下载 https://edelivery.oracle.com/EPD/Download/get_form?egroup_aru_number=14841438 https://edelivery.oracle.com/EPD/Download/get_form?egroup_aru_number=14841440

异构平台之间的配置DataGuard的情况说明

在部署DataGuard时,最简单的情况是主/备节点配置完全相同的.但是,有时会碰巧会有在异构操作系统上进行部署的情况,以便于从异构平台之间进行数据迁移能有最小的停机时间或风险.为用户通过配置异构的处理能力或硬件成本较低的备用系统,以减少在灾备上的投资,这也是全理的方案.使用提供这种配置的说明信息,以确定哪些平台组合能进行Data Guard的配置,以及任何额外的要求或限制是否在可能适用的范围. 如果考虑使用一个异构的主/备DataGuard配置,Oracle建议用户进行充分的测试,并确保Dat

“跑路风波”的内在缘由?P2P网络信贷将何去何从?

据报道,今年6月倒闭的网贷平台多达7家,其中有3家跑路.4家涉嫌诈骗.浙江的恒金贷仅仅上线半天便失去联系而被称为跑路最快的平台.此外,北京地区首次出现P2P平台跑路现象,打破了北京网贷行业安全性极高.不存在跑路平台的"神话".另一方面,据网贷之家发布的<2014中国网络借贷行业上半年年报>显示,全国共有1184家P2P平台,已经超越美国成为全球最大的P2P交易市场.上半年,全国P2P网贷成交额为964.46亿元,较去年下半年的600.64亿元增加363.82亿元,增长60.

NetworkComms c#通信框架与Java的Netty框架通信 解决粘包问题

上次写了一篇文章  基于networkcomms V3通信框架的c#服务器与java客户端进行通信之Protobuf探讨 其中没有解决粘包问题,抛砖引玉,文章得到了失足程序员 老师的点评,并给出了解决方案:[最多评论]java netty socket库和自定义C#socket库利用protobuf进行通信完整实例(10/591) » 于是马上开始学习,并把c#服务器端换成了我比较熟悉的networkcomms v3 c#通信框架(商业版,本文并不提供) ,以方便与已经存在的系统进行整合. 客户

异步tcp通信——APM.Core 解包

TCP通信解包 虽说这是一个老生长谈的问题,不过网上基本很少见完整业务:或多或少都没有写完或者存在bug.接收到的数据包可以简单分成:小包.大包.跨包三种情况,根据这三种情况作相对应的拆包处理,示例如下: 1 /***************************************************************************************************** 2 * 本代码版权归@wenli所有,All Rights Reserved (C)