三种数据包组包方案(map+array)

1、Introduction And Question

        最近在做网关项目,在进行隧道转发的时候会加上很多协议头部,可能用户那边没有超出MTU大小,加了这些协议头部后就大于MTU了。由于网关转发的时候使用的内核协议栈的UDP,会自动进行分包转发。项目组的大佬担心防火墙会拦截UDP分片的包,所以咱得自己做分包组包,目的是使网关发出去的每一个包都得具备完整的IP与UDP头部。

        我的思路是使用map,因为分片的时候给每个包自定义(ID、DF、MF),在接收端网关先判断DF,如果没有分片,则校验解封装后转发,万事大吉;对于分片的数据包,提取ID,查找本地是否存有分片,如果存在则组装后再校验解封装转发出去(实际上最多分两片,所以本地存在的话,新来的肯定是缺失的)。

        上面的思路存在一个问题:如何管理map,总不可能无休止的往map里塞值吧。

2、Answer

        下面提供了三种思路。

        第一种:看下图,通过设置一个定长的数组来约束map的长度。数组中元素是KEY类型的(KEY是map的主键),当往map中新增键值对时在数组中记录下KEY,当数组的Index超出数组长度时,则从头开始覆盖数组旧的KEY,覆盖的时候根据KEY删除map中的键值对。这样就可以确定一个定长的map啦。

         还存在另一种解体思路。其实内存应避免重复的new/delete ,最好是申请一块大内存,然后自己去管理这块内存。而且在go中map delete操作并不会真的释放空间,只是标记(https://github.com/golang/go/issues/new)。我们按照下面一种思路来进行。

        如下图,将上面的数组与map角色互换。即map用来存取数组的index,数组用来存放数据包。数组的使用和上面思路相仿,即新数据覆盖旧数据,而且现在可以确保申请的空间时固定的(数组长度约束着呢)。通过这样复用数组的空间,可以很好的管理内存空间,不用担心内存泄漏啦;而且还实现了快速查找(新来的数据包,提取ID,查找到index,从数组中提取数据)。

        那么存放数组index的map如何管理呢?其实很简单,在数组中覆盖旧数据的时候,根据ID删除map中的数据即可。

        上面的方案其实还是存在一些缺点,即属于数组的大小必须根据设备的吞吐量来设置。因为对于已经组包成功的,数组无法直接删除,只能等待数组指针循环回来进行覆盖;这样在高吞吐量(包进来的速度超出处理速度)的时候数组可能会很快填满,指针可能很快就会回头覆盖还没有处理完的节点(时间戳),主要是因为对于处理完的数据包数组无法删除,数组的内存利用率很低。

         解决方案是使用双向循环链表,对于已经处理完的节点直接释放节点空间,处理多少就释放多多,这样内存的使用效率就上来了。而且链表中第一个节点时间上肯定是最久远的,等到链表长度到达限制则可以没有顾虑的删除。

         举一个不那么恰当的吃席的例子。第二种方法类似一桌一桌的吃,一桌吃完了才能组第二桌吃饭,即使有人已经吃完走人了,也不会有人凑过去坐他位置吃饭;第三种方法像是流水席,吃完走人后,位置腾出来给别人用。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我要出家当道士

打赏是不可能,这辈子都不可能

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值