ns2中收发的数据包一般都需要排队,也就是说数据包需要组成一个FIFO的队列。队列的形成与Packet类有关。
Packet类在/ns-allinone-2.35/ns-2.35/common/packet.h中定义(HDR_CMN在同一个文件中定义)。
class Packet : public Event { private: unsigned char* bits_; // header bits // unsigned char* data_; // variable size buffer for 'data' // unsigned int datalen_; // length of variable size buffer AppData* data_; // variable size buffer for 'data' static void init(Packet*); // initialize pkt hdr bool fflag_; protected: static Packet* free_; // packet free list int ref_count_; // free the pkt until count to 0 public: Packet* next_; // for queues and the free list static int hdrlen_; Packet() : bits_(0), data_(0), ref_count_(0), next_(0) { } inline unsigned char* bits() { return (bits_); } inline Packet* copy() const; inline Packet* refcopy() { ++ref_count_; return this; } inline int& ref_count() { return (ref_count_); } static inline Packet* alloc(); static inline Packet* alloc(int); inline void allocdata(int); // dirty hack for diffusion data inline void initdata() { data_ = 0;} static inline void free(Packet*); inline unsigned char* access(int off) const { if (off < 0) abort(); return (&bits_[off]); } // This is used for backward compatibility, i.e., assuming user data // is PacketData and return its pointer. inline unsigned char* accessdata() const { if (data_ == 0) return 0; assert(data_->type() == PACKET_DATA); return (((PacketData*)data_)->data()); } // This is used to access application-specific data, not limited // to PacketData. inline AppData* userdata() const { return data_; } inline void setdata(AppData* d) { if (data_ != NULL) delete data_; data_ = d; } inline int datalen() const { return data_ ? data_->size() : 0; } // Monarch extn static void dump_header(Packet *p, int offset, int length); // the pkt stamp carries all info about how/where the pkt // was sent needed for a receiver to determine if it correctly // receives the pkt PacketStamp txinfo_; /* * According to cmu code: * This flag is set by the MAC layer on an incoming packet * and is cleared by the link layer. It is an ugly hack, but * there's really no other way because NS always calls * the recv() function of an object. * */ u_int8_t incoming; //monarch extns end; };
Packet的构造函数如下:
Packet() : bits_(0), data_(0), ref_count_(0), next_(0) { }
初始化列表分别包括了指向数据包头部的指针bits_,指向数据的指针data_,数据包长度ref_count以及指向队列下一个元素的指针next_。
在实现以Packet为元素的队列时,只需要添加两个指针,分别指向队列的头部和尾部即可。
以AOMDV协议中的队列为例:
class aomdv_rqueue : public Connector { public: aomdv_rqueue(); void recv(Packet *, Handler*) { abort(); } void enque(Packet *p); inline int command(int argc, const char * const* argv) { return Connector::command(argc, argv); } /* * Returns a packet from the head of the queue. */ Packet* deque(void); /* * Returns a packet for destination "D". */ Packet* deque(nsaddr_t dst); /* * Finds whether a packet with destination dst exists in the queue */ char find(nsaddr_t dst); private: Packet* remove_head(); void purge(void); void findPacketWithDst(nsaddr_t dst, Packet*& p, Packet*& prev); bool findAgedPacket(Packet*& p, Packet*& prev); void verifyQueue(void); Packet *head_; Packet *tail_; int len_; int limit_; double timeout_; };之后通过操作*head_和*tail_就可以对队列进行入队,出队,查找等操作了。