今天讨论了一个半小时,为什么要在应用层进行转译?
这精妙的设计,一是为了提高寻找完整帧的效率,二是通过填充字节避免了因干扰导致数据翻转成帧尾的情况。

精妙在3点:

1、先找帧尾,而不是头,是因为转译后尾巴是唯一的,而头不是,这样可以大大提高效率。而如果不转译,为了确保帧的正确性,帧头+长度+帧尾并不能规避数据中的巧合问题,每次遇到这种巧合还需要另外计算CRC判断,这相当于每个数据中的尾巴都要找一下帧尾、偶尔巧合还得计算CRC,而如果早在数据源就把所有数据中的尾巴都替换掉,就省下了巧合需要计算CRC的步骤。肯定转译效率更高:
转译:全量扫描,替换掉数据中的尾巴。后面再全量扫描找唯一帧尾,跳到帧头。
不转译:全量扫描,遇到数据中的帧尾时,跳到帧头,偶尔巧合还要再计算下CRC。

另外,转译和不转译体现了两种思想:
转译是,从源头上排除数据中出现帧尾的情况,发送方提前进行了一个全量扫描和替换,保证了帧尾的唯一性,接收方先依据唯一帧尾找到完整帧后再进行一个反向的全量替换。
不转译是,发送方允许数据中出现帧尾,接收方全量扫描时,遇到了再单独判断、实在不行上CRC排除错误。只是遇到假帧尾是不敢丢的。

全帧长度为n时,二者的时间复杂度如下:
转译:O(n+n+n+m) = O(3n+m)
不转译:O(n+im+kn^2),i为数据中帧尾个数、m为通过帧尾找帧头的时间,k为巧合的个数
所以,正常多时不转译效率高,异常多时转译效率高。

2、转译尾巴、而非头,是为了先找尾巴,再往前找头,如果找不到头,就把尾巴和前面的数据直接丢掉。如果扫描时先找头,则只能一个字节一个字节扫描,不能直接丢掉没有尾巴的错误帧。这也解释了为什么长度放到尾部,而非放到头部,因为尾巴前面就是长度,就可以直接跳到头,判断是否正确!

3、帧头、帧尾,和填充都设计的非常精妙,防止了干扰导致数据变成唯一帧尾的情况。
转译也因为增加填充字节拉长了数据,避免了因干扰而导致数据变成帧尾的情况。因为数据中出现的尾巴是“005AFE”,而真正的尾巴是“AA5AFE”,00交叉翻转成AA,几乎不可能。
如果不转译,数据中的“5AFF”或“4AFE”等翻转成“5AFE”是非常容易的。

为什么帧头设置为0X5A54,帧尾设置成0X5AFE?
为了防止电波交叉翻转!
5A的二进制是

电波为什么要以1b90开头?是因为自然界不存在的电波。

感悟?
1、不要过多依赖过去经验和寻求大牛帮助,而是从第一性原理出发,从底层逻辑思考原因。每个人都有这样的能力。
2、思考时不要泛泛而谈猜测大概的原因,比如说以前都这么干的,可能是抄的TCP/IP的链路层协议,可能是曾经内存bufer不够只能一个字节一个字节接收,这都是浅表的泛泛猜测,没有真正深入具体实现场景和逻辑,不是真正的根源。一定要追究真正的原因,具体探讨他的实现逻辑和场景,每一个细节都搞明白,才能一步步抽丝剥茧找到真正的原因。
3、讨论。4个人,分别从不同角度考虑,凑在一起,解决了信息不对称问题和单一思维定势,也就逐渐抽丝剥茧找到了问题根源。
QH,一定要弄明白为什么?弄明白干扰时导致的可能性?好问题,刨根问底的探究精神,讨论发起者。
XL,转译思考到效率问题,注意到长度在帧尾,一针见血说清楚小问题,思考错误场景。联系能力,拆解问题,表述能力。
SH,提供了从帧尾开始找,而非帧头。客观解法。
XX,提供了帧尾丢的快的思路。客观解法,猜测为了丢帧更高效。

posted on 2024-06-26 18:41  西伯尔  阅读(8)  评论(0编辑  收藏  举报