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_就可以对队列进行入队,出队,查找等操作了。