理解NS2中Packet的包頭

   ns2中的數據包全部是由Packet進行表示的,當我們需要創建一個新的數據包時,就調用Packet::alloc方法,下面看看Packet::alloc都做了什麼:
inline Packet* Packet::alloc()
{
     Packet* p = free_;
     if (p != 0) {
         assert(p->fflag_ == FALSE);
         free_ = p->next_;
         assert(p->data_ == 0);
         p->uid_ = 0;
         p->time_ = 0;
     } else {
         p = new Packet;
         p->bits_ = new unsigned char[hdrlen_];
         if (p == 0 || p->bits_ == 0)
              abort();
     }
     init(p); // Initialize bits_[]
     (HDR_CMN(p))->next_hop_ = -2; // -1 reserved for IP_BROADCAST
     (HDR_CMN(p))->last_hop_ = -2; // -1 reserved for IP_BROADCAST
     p->fflag_ = TRUE;
     (HDR_CMN(p))->direction() = hdr_cmn::DOWN;
     /* setting all direction of pkts to be downward as default;
        until channel changes it to +1 (upward) */
     p->next_ = 0;
     return (p);
}
問題出現了,看這行
p->bits_ = new unsigned char[hdrlen_];
hdrlen_是從哪來的,在哪裏初始化的?
在C++代碼中一搜,發現了這樣的語句:
     PacketHeaderManager() {
         bind("hdrlen_", &Packet::hdrlen_);
     }
原來Packet::hdrlen_被綁定到PacketHeaderManager這個OTCL類了。
繼續在tcl文件中搜索,發現了這樣的一個函數:
PacketHeaderManager instproc allochdr cl {
     set size [$cl set hdrlen_]
 
     $self instvar hdrlen_
     set NS_ALIGN 8
     # round up to nearest NS_ALIGN bytes
     # (needed on sparc/solaris)
     set incr [expr ($size + ($NS_ALIGN-1)) & ~($NS_ALIGN-1)]
     set base $hdrlen_
     incr hdrlen_ $incr
 
     return $base
}
哈哈,原來PacketHeaderManager每增加一個包頭的定義,就把這個包頭的長度加起來,難怪在NS2的文檔中說要刪除不必要的包頭定義!!
再看看allochdr是由誰調用的?
Simulator instproc create_packetformat { } {
     PacketHeaderManager instvar tab_
     set pm [new PacketHeaderManager]
     foreach cl [PacketHeader info subclass] {
         if [info exists tab_($cl)] {
              set off [$pm allochdr $cl]
              $cl offset $off
         }
     }
     $self set packetManager_ $pm
}
清楚了吧,在創建Simulator時,它將把所有啓動的數據包的包頭長度加起來,因此文檔中又說對數據包頭的增刪應該在Simulator創建之前,原因就在這裏。
下一個問題,如何訪問指定包頭中的數據?
在NS2中,每個不同的數據包都必須從PacketHeaderClass這個C++類繼承一個子類,並在構造函數中調用PacketHeaderClass::bind_offset方法,看看這個函數做了什麼:
inline void bind_offset(int* off) { offset_ = off; }
就是保存了一個偏移量的指針而已,通常這個偏移量是存放在hdr*::offset_中的。
PacketHeaderClass這個類還實現了一個叫做offset的方法可以讀取和設置偏移量。
int PacketHeaderClass::method(int ac, const char*const* av)
{
     Tcl& tcl = Tcl::instance();
     int argc = ac - 2;
     const char*const* argv = av + 2;
     if (argc == 3) {
         if (strcmp(argv[1], "offset") == 0) {
              if (offset_) {
                   *offset_ = atoi(argv[2]);
                   return TCL_OK;
              }
              tcl.resultf("Warning: cannot set offset_ for %s",
                       classname_);
              return TCL_OK;
         }
     }
     else if (argc == 2) {
         if (strcmp(argv[1], "offset") == 0) {
              if (offset_) {
                   tcl.resultf("%d", *offset_);
                   return TCL_OK;
              }
         }
     }
     return TclClass::method(ac, av);
}
這樣當在OTCL中調用“offset ?大小?”時,這個指定的值就被保存到hdr*::offset_這個變量中了。
再看看上面的create_packetformat方法,在這一行:
$cl offset $off
就調用了PacketHeaderClass的offset方法設置這個數據包的偏移量,這樣我們通過包頭的頭指針和偏移量就可以訪問到指定的包頭了。
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章