refer
packet官网的module
packet doxygen
item
- stuct Item
实际上是一个小细胞、小组成体的感觉(一个结构的基本组成框架)
比如说在block-ack-manager.h里面他就是:
/**
* A struct that holds information about a packet for putting
* in a packet queue.
*/
结构体包含三个元素:
* \param packet*斜体样式*
* \param hdr
* \param tstamp
在packet的元数据信息里面,他就包含:
struct Item
{
/// Type of data in the packet
enum ItemType {
PAYLOAD, //!< Payload
HEADER, //!< Header
TRAILER //!< Trailer
} type; //!< metadata type
...... //当然他还包含了一些其他的东西 比如 bool isFragment之类的
/**结构体,保存了一个包的信号,该包存放在包队列中。
* typedef for packet (struct Item) queue.
*/
typedef std::list<struct Item> PacketQueue;包队列
packet & tag
overview
- 每个网络数据包包含一个字节缓冲区,一组字节标签,一组数据包标签和元数据。
- 开发人员通常希望将数据存储在实际数据包中找不到的数据包对象中(例如时间戳或流ID)。Packet类通过存储一组标签(Tag类)来满足此要求。
这些标签有两类用例,这导致了两种不同类型的标签。所谓的“byte”标签用于标记分组字节缓冲区中字节的子集,而“packet”标签用于标记分组本身。两种标签之间的主要区别是复制,分段和重新组合数据包时会发生什么:“byte”标签紧随字节,而“packet”标签紧随数据包。这两种标签之间的另一个重要区别是byte标签无法删除,只能写入一次并读取多次,而packet标签只能写入一次,读取多次,并删除了一次。“byte”标签的一个示例是FlowIdTag,其中包含流ID,由生成流量的应用程序设置。“packet”标签的一个示例是由应用程序设置并由较低级别的MAC层处理的跨层QoS类ID。
header & trailer
- Packet类旨在廉价复制。总体设计基于写入时复制(COW)。当有多个对包对象的引用,并且其中有一个操作时,只有所谓的“脏”操作才会触发包的深层副本:
ns3::Packet::AddHeader()
ns3::Packet::AddTrailer()
both versions of ns3::Packet::AddAtEnd()
Packet::RemovePacketTag()
- 用于添加和删除字节缓冲区的基本类是Header和Trailer。Header更常见,但module里面的讨论也很大程度上适用于使用trailers的协议。
需要从Packet实例中插入和删除的每个协议标头都应从抽象Header基类派生并实现下面列出的私有纯虚拟方法:
ns3::Header::SerializeTo()
ns3::Header::DeserializeFrom()
ns3::Header::GetSerializedSize()
ns3::Header::PrintTo()
前三个功能用于将协议控制信息串行化和反序列化到缓冲区或从缓冲区反序列化。例如,可以定义 class TCPHeader : public Header。TCPHeader对象通常由一些私有数据(如序列号)和公共接口访问功能(如检查输入范围)组成。但是,数据包缓冲区中TCPHeader的基本表示形式是20个序列化字节(加上TCP选项)。因此,TCPHeader :: SerializeTo()函数将被设计为以网络字节顺序将这20个字节正确地写入数据包。最后一个函数用于定义Header对象如何将自身打印到输出流上。
或更多细节参见官网。
tag
- 可以将用户定义的标签附加到数据包。与Header不同,标签不会序列化到连续的缓冲区中,而是存储在列表中。标签可以灵活地定义为任何类型,但是在任何时候标签缓冲区中只能有一个特定对象类型的实例。
detail
-
ByteTag跟随字节,而PacketTag跟随数据包。这意味着在对数据包进行操作(例如分段,串联以及附加或删除标头)时,字节标记会跟踪它们所覆盖的数据包字节。例如,如果用户创建一个TCP段,并将ByteTag应用于该段,则将标记该TCP段的每个字节。但是,如果下一层插入IPv4标头,则此ByteTag将不会覆盖这些字节。Packet Tag则相反;尽管对其进行了操作,但它仍然覆盖一个数据包。
-
PacketTag的大小限制为20个字节。这是中的可修改编译时常量src/network/model/packet-tag-list.h。ByteTag没有这样的限制。
-
每种标签类型都必须是ns3::Tag的子类,并且每种标签类型中只能有一个实例。
-
数据包标签和字节标签行为上的一些差异。
- 分段: 如上所述,当一个数据包被分段时,每个数据包分段(是一个新数据包)将获得所有数据包标签的副本,而字节标签将遵循新的数据包边界(即,如果分段的数据包跨缓冲区分段)字节标记所覆盖的区域,两个数据包片段仍将具有标记为字节的适当缓冲区。
- 串联:将数据包合并后,两个不同的缓冲区将变为一个。对于字节标签,字节标签仅跟随相应的缓冲区。对于数据包标签,只有第一个数据包上的标签才能在合并中幸存。
- 查找和打印:这两个类都允许您遍历所有标签并进行打印。
- 删除:用户可以在单个数据包上多次添加和删除相同的数据包标签(AddPacketTag()和RemovePacketTag())。但是,一旦添加了字节标记,则只能通过从数据包中剥离所有字节标记将其删除。当前API不支持删除可能的多个字节标签之一。
-
从ns-3.5及更高版本开始,在调用Packet::Serialize ()和Packet::Deserialize ()时,Tag不会被序列化和反序列化到缓冲区 。这是一个open bug。
-
如果用户要获取现有的数据包对象并将其用作新数据包,则他或她应先删除所有字节标签和数据包标签,然后再这样做。一个示例是UdpEchoServer类,该类接收接收到的数据包并“转过来”以发送回回显客户端。
源码阅读与学习
- FlowIdTag.cc
- UdpEchoServer.cc
- packet.cc
- main-packet-tag.cc
- 仿写的时候要确定分片操作会怎么办
packet tag会被复制
- packet-list.cc
设计得很有意思,有空读一下他的设计模式
attention
一些细节注意
- packet->GetSize()是把头部(还有尾部)信息加进去的,但是不包括tag的字节数。