如何新增或修改ns2的核心模組--queue management
?????? 原文地址 :http://140.116.72.80/~smallko/ns2/module.htm
?
這個章節(jié)最主要的目的就是希望使用者可以學(xué)會如何新增或修改ns2的核心模組,更明確的說就是去新增和修改[*.cc, *.h]檔案,以筆者和筆者朋友學(xué)習(xí)ns2的經(jīng)驗來說,這需要花很多時間和很大的勇氣,時間是花來找資料,勇氣是用來承受當(dāng)程式寫不好時,ns2可能隨時會當(dāng)?shù)簟2贿^別怕,只要跟著筆者所介紹的方法,一定可以成功,若是不成功,就寫信給筆者吧。
??????? 若是一開始就要叫ns2的新手去增加的模組,新手一定會哇哇叫,所以筆者不會這樣做,筆者先教大家拷貝ns2已經(jīng)有的模組檔,但改成別的名字,這樣就可以輕鬆且很明確知道該如何增加模組。
?
<!--[if !supportLists]-->(1)??? <!--[endif]-->打開cygwin的命令視窗,把路徑切換到queue的目錄下。
cd? ns-allinone-2.27/ns-2.27/queue
?
<!--[if !supportLists]-->(2)??? <!--[endif]-->拷貝drop-tail.[cc, h]到myfifo.[cc.h]。
cp? drop-tail.cc? myfifo.cc
cp? drop-tail.h?? myfifo.h
?
<!--[if !supportLists]-->(3)??? <!--[endif]-->使用文字編輯軟體去修改myfifo.h和myfifo.cc。(因為我們的環(huán)境是在windows下,所以建議可以使用ultra-edit來修改。
<!--[if !supportLists]-->a.?????? <!--[endif]-->先修改myfifo.h,使用取代的功能把所有DropTail改成myfifo,另外,把drop_tail改成myfifo。
#ifndef ns_myfifo_h
#define ns_myfifo_h
?
#include <string.h>
#include "queue.h"
#include "config.h"
?
/*
?* A bounded, drop-tail queue
?*/
class myfifo : public Queue {
? public:
??????? myfifo() {
??????????????? q_ = new PacketQueue;
??????????????? pq_ = q_;
??????????????? bind_bool("drop_front_", &drop_front_);
??????????????? bind_bool("summarystats_", &summarystats);
??????????????? bind_bool("queue_in_bytes_", &qib_);? // boolean: q in bytes?
??????????????? bind("mean_pktsize_", &mean_pktsize_);
??????????????? //????????????? _RENAMED("drop-front_", "drop_front_");
??????? }
??????? ~myfifo() {
??????????????? delete q_;
??????? }
? protected:
??????? void reset();
??????? int command(int argc, const char*const* argv);
??????? void enque(Packet*);
??????? Packet* deque();
??????? void shrink_queue(); // To shrink queue and drop excessive packets.
??????? PacketQueue *q_;??? /* underlying FIFO queue */
??????? int drop_front_;??????? /* drop-from-front (rather than from tail) */
??????? int summarystats;
??????? void print_summarystats();
??????? int qib_;?????? ????? /* bool: queue measured in bytes? */
??????? int mean_pktsize_;??? /* configured mean packet size in bytes */
};
?
#endif
?
<!--[if !supportLists]-->b.????? <!--[endif]-->再修改myfifo.cc,使用取代的功能把所有DropTail改成myfifo,另外,把drop_tail改成myfifo和drop-tail改成myfifo。
#include "myfifo.h"
?
static class myfifoClass : public TclClass {
?public:
??????? myfifoClass() : TclClass("Queue/myfifo") {}
??????? TclObject* create(int, const char*const*) {
??????????????? return (new myfifo);
??????? }
} class_myfifo;
?
void myfifo::reset()
{
??????? Queue::reset();
}
?
int myfifo::command(int argc, const char*const* argv) {
??????? if (argc==2) {
??????????????? if (strcmp(argv[1], "printstats") == 0) {
??????????????????????? print_summarystats();
??????????????????????? return (TCL_OK);
??????????????? }
?????????????? if (strcmp(argv[1], "shrink-queue") == 0) {
?????????????????????? shrink_queue();
?????????????????????? return (TCL_OK);
?????????????? }
??????? }
??????? if (argc == 3) {
??????????????? if (!strcmp(argv[1], "packetqueue-attach")) {
??????????????????????? delete q_;
??????????????????????? if (!(q_ = (PacketQueue*) TclObject::lookup(argv[2])))
??????? ??????????????????????? return (TCL_ERROR);
??????????????????????? else {
??????????????????????????????? pq_ = q_;
??????????????????????????????? return (TCL_OK);
??????????????????????? }
??????????????? }
??????? }
??????? return Queue::command(argc, argv);
}
?
/*
?* drop-tail
?*/
void myfifo::enque(Packet* p)
{
??????? if (summarystats) {
??????????????? Queue::updateStats(qib_?q_->byteLength():q_->length());
??????? }
?
??????? int qlimBytes = qlim_ * mean_pktsize_;
??????? if ((!qib_ && (q_->length() + 1) >= qlim_) ||
? ??? (qib_ && (q_->byteLength() + hdr_cmn::access(p)->size()) >= qlimBytes)){
??????????????? // if the queue would overflow if we added this packet...
??????????????? if (drop_front_) { /* remove from head of queue */
??????????????????????? q_->enque(p);
??????????????????????? Packet *pp = q_->deque();
??????????????????????? drop(pp);
??????????????? } else {
??????????????????????? drop(p);
??????????????? }
??????? } else {
??????????????? q_->enque(p);
??????? }
}
?
//AG if queue size changes, we drop excessive packets...
void myfifo::shrink_queue()
{
??????? int qlimBytes = qlim_ * mean_pktsize_;
??????? if (debug_)
??????????????? printf("shrink-queue: time %5.2f qlen %d, qlim %d/n",
?????????????????????? Scheduler::instance().clock(),
??????????????????????? q_->length(), qlim_);
??????? while ((!qib_ && q_->length() > qlim_) ||
??????????? (qib_ && q_->byteLength() > qlimBytes)) {
??????????????? if (drop_front_) { /* remove from head of queue */
??????????????????????? Packet *pp = q_->deque();
??????????????????????? drop(pp);
??????????????? } else {
??????????????????????? Packet *pp = q_->tail();
????????????????? ??????q_->remove(pp);
??????????????????????? drop(pp);
??????????????? }
??????? }
}
?
Packet* myfifo::deque()
{
??????? if (summarystats && &Scheduler::instance() != NULL) {
??????????????? Queue::updateStats(qib_?q_->byteLength():q_->length());
??????? }
??????? return q_->deque();
}
?
void myfifo::print_summarystats()
{
??????? //double now = Scheduler::instance().clock();
??????? printf("True average queue: %5.3f", true_ave_);
??????? if (qib_)
??????????????? printf(" (in bytes)");
??????? printf(" time: %5.3f/n", total_time_);
}
?
<!--[if !supportLists]-->(4)??? <!--[endif]-->修改ns-default.tcl檔,設(shè)定初始內(nèi)定值。
<!--[if !supportLists]-->a.?????? <!--[endif]-->cd? ns-allinone-2.27/ns-2.27/tcl/lib/
<!--[if !supportLists]-->b.????? <!--[endif]-->使用文字編輯軟體打開ns-default.tcl
<!--[if !supportLists]-->c.?????? <!--[endif]-->使用搜尋的功能找到Queue/DropTail
<!--[if !supportLists]-->d.????? <!--[endif]-->把每個初始設(shè)定值都再設(shè)一份給Queue/myfifo
……………………………………………..
?? Queue/DropTail set drop_front_ false
Queue/DropTail set summarystats_ false
Queue/DropTail set queue_in_bytes_ false
Queue/DropTail set mean_pktsize_ 500
?
Queue/myfifo set drop_front_ false
Queue/myfifo set summarystats_ false
Queue/myfifo set queue_in_bytes_ false
Queue/myfifo set mean_pktsize_ 500
……………………………………………..
?
<!--[if !supportLists]-->(5)??? <!--[endif]-->修改Makefile,把myfifo.o加入OBJ_CC內(nèi),並重新編譯。
<!--[if !supportLists]-->a.?????? <!--[endif]-->使用文字編輯軟體打開ns-allinone-2.27/ns-2.27目錄下的Makefile
<!--[if !supportLists]-->b.????? <!--[endif]-->使用搜尋找到drop-tail.o。
<!--[if !supportLists]-->c.?????? <!--[endif]-->在drop-tail.o後面加上queue/myfifo。
……………………………………………..
tools/flowmon.o tools/loss-monitor.o /
queue/queue.o queue/drop-tail.o? queue/myfifo.o /
adc/simple-intserv-sched.o queue/red.o /
……………………………………………
<!--[if !supportLists]-->d.????? <!--[endif]-->重新編譯。
make
?
??????? 若是沒有什麼錯誤訊息產(chǎn)生,就是編譯成功。如下圖所示。
測試一下新安裝的模組是否可以正常的運(yùn)作。可以把修改基本工具章節(jié)中的範(fàn)例,把DropTail改成myfifo,試看看跑出來的結(jié)果是否跟用DropTail跑出來的一樣。
?
在這邊先做個小結(jié),如何新增模組到ns2的核心步驟如下:
1.準(zhǔn)備好模組檔(例如,a.cc 和 a.h)。
2.若有需要做初始設(shè)定的話,修改ns-default.tcl檔。
3.修改Makefile(把a.o加到OBJ_CC內(nèi))
4.重新編譯
5.測試模組
?
關(guān)於如何去寫C++的模組檔案,並不包含在這份文件內(nèi)。因為每個模組的功能都不相同,但筆者可以給使用者一些建議,因為ns2內(nèi)已經(jīng)有很多類型的模組檔案,使用者可以根據(jù)不同的需要,找到最相近的模組檔,然後再去修改,以這樣的方式會比較容易把自己所需要的模組加入ns2的核心。
?
繼續(xù)新的主題前,筆者要告訴使用者在C++程式內(nèi)非常重要的地方,第一個是bind相關(guān)函數(shù),以前面的myfifo為例,在myfifo.h程式碼內(nèi):
class myfifo : public Queue {
? public:
??????? myfifo() {
??????????????? q_ = new PacketQueue;
??????????????? pq_ = q_;
??????????????? bind_bool("drop_front_", &drop_front_);
??????????????? bind_bool("summarystats_", &summarystats);
??????????????? bind_bool("queue_in_bytes_", &qib_);? // boolean: q in bytes?
??????????????? bind("mean_pktsize_", &mean_pktsize_);
??????????????? //????????????? _RENAMED("drop-front_", "drop_front_");
??????? }
……………………………………………..
可以看到bind或者是bind_bool,這兩個函數(shù)主要的目的是要把TCL的變數(shù)和C++的變數(shù)產(chǎn)生互連的關(guān)係,這樣使用者就可以在TCL檔內(nèi)去設(shè)定或者去查看目前C++的變數(shù)值。(bind_bool是用在布林變數(shù),bind是用在一般實數(shù);而第一個參數(shù)是TCL的變數(shù),第二個參數(shù)是C++內(nèi)的變數(shù)。) 筆者以在基本工具內(nèi)的範(fàn)例為例,教大家如何去改變或查看C++的變數(shù)值。
?
[範(fàn)例一:設(shè)定C++的參數(shù)值]
一般而言,FiFo queue的行為都是當(dāng)佇列內(nèi)的暫存區(qū)滿了以後,就會把新進(jìn)的封包所丟棄,這是因為在ns-default.tcl初始設(shè)定檔內(nèi) drop_front_是設(shè)成false。但是如果想要改變成當(dāng)暫存區(qū)滿了時候,要把佇列暫存區(qū)最前面的封包所丟棄,則可以在TCL內(nèi)使用:
?
#以n2到n3之間的的佇列為例
set qn2n3_ [[$ns link $n2 $n3] queue]
$qn2n3_ set drop_front_ true
?
[範(fàn)例二:如何去查看即時C++的參數(shù)值]
筆者以基本工具篇的範(fàn)例為例,教大家如何量測FTP那條TCP flow的congestion window變化。
# 產(chǎn)生一個模擬的物件
set ns [new Simulator]
?
#針對不同的資料流定義不同的顏色,這是要給NAM用的
$ns color 1 Blue
$ns color 2 Red
?
#開啟一個NAM trace file
set nf [open out.nam w]
$ns namtrace-all $nf
?
#開啟一個trace file,用來記錄封包傳送的過程
set nd [open out.tr w]
$ns trace-all $nd
?
#開啟一個檔案,用來記錄TCP Flow的congestion window變化情況
set wnd_trace [open cwnd.tr w]
?
#定義一個紀(jì)錄的程序,每隔0.1秒就去查看目前TCP Flow的值
proc record {} {
global ns tcp wnd_trace
set time 0.1
??????? ?
#讀取C++內(nèi)cwnd_的變數(shù)值
set curr_cwnd [$tcp set cwnd_]
??? set now [$ns now]
??? puts $wnd_trace "$now?? $ curr_cwnd "
??? $ns at [expr $now+$time] "record"
}??????
?
#定義一個結(jié)束的程序
proc finish {} {
??????? global ns nf nd wnd_trace
??????? $ns flush-trace
??????? close $nf
??????? close $nd
??????? close $wnd_trace
??????? #以背景執(zhí)行的方式去執(zhí)行NAM
??????? #exec nam out.nam &
??????? exit 0
}
?
#產(chǎn)生四個網(wǎng)路節(jié)點(diǎn)
set n0 [$ns node]
set n1 [$ns node]
set n2 [$ns node]
set n3 [$ns node]
?
#把節(jié)點(diǎn)連接起來
$ns duplex-link $n0 $n2 2Mb 10ms DropTail
$ns duplex-link $n1 $n2 2Mb 10ms DropTail
$ns duplex-link $n2 $n3 1.7Mb 20ms DropTail
?
set qn2n3_ [[$ns link $n2 $n3] queue]
?
#設(shè)定ns2到n3之間的Queue Size為10個封包大小
$ns queue-limit $n2 $n3 10
?
#設(shè)定節(jié)點(diǎn)的位置,這是要給NAM用的
$ns duplex-link-op $n0 $n2 orient right-down
$ns duplex-link-op $n1 $n2 orient right-up
$ns duplex-link-op $n2 $n3 orient right
?
#觀測n2到n3之間queue的變化,這是要給NAM用的
$ns duplex-link-op $n2 $n3 queuePos 0.5
?
#建立一條TCP的連線
set tcp [new Agent/TCP]
$tcp set class_ 2
$ns attach-agent $n0 $tcp
set sink [new Agent/TCPSink]
$ns attach-agent $n3 $sink
$ns connect $tcp $sink
#在NAM中,TCP的連線會以藍(lán)色表示
$tcp set fid_ 1
?
#在TCP連線之上建立FTP應(yīng)用程式
set ftp [new Application/FTP]
$ftp attach-agent $tcp
$ftp set type_ FTP
?
#建立一條UDP的連線
set udp [new Agent/UDP]
$ns attach-agent $n1 $udp
set null [new Agent/Null]
$ns attach-agent $n3 $null
$ns connect $udp $null
#在NAM中,UDP的連線會以紅色表示
$udp set fid_ 2
?
#在UDP連線之上建立CBR應(yīng)用程式
set cbr [new Application/Traffic/CBR]
$cbr attach-agent $udp
$cbr set type_ CBR
$cbr set packet_size_ 1000
$cbr set rate_ 1mb
$cbr set random_ false
?
#設(shè)定FTP和CBR資料傳送開始和結(jié)束時間
$ns at 0.1 "$cbr start"
$ns at 1.0 "$ftp start"
$ns at 1.1 "record"
$ns at 4.0 "$ftp stop"
$ns at 4.5 "$cbr stop"
?
#結(jié)束TCP的連線(不一定需要寫下面的程式碼來實際結(jié)束連線)
$ns at 4.5 "$ns detach-agent $n0 $tcp ; $ns detach-agent $n3 $sink"
?
#在模擬環(huán)境中,5秒後去呼叫finish來結(jié)束模擬(這樣要注意模擬環(huán)境中
#的5秒並不一定等於實際模擬的時間
$ns at 5.0 "finish"
?
#執(zhí)行模擬
$ns run
?
然後使用gnuplot,設(shè)定環(huán)境變數(shù)
set xtics 1,0.2,4
set xrange [1:4]
plot “cwnd.tr” with lines
?
第二個要注意的地方是在C++程式碼內(nèi)的command程序,這個command程序可以讓TCL去呼叫C++的命令。
例如$ftp start、$ftp stop中的”start”和”stop”都是去呼叫C++模組內(nèi)的命令。所以使用者若是在寫C++模組程式時,要提供一些程序給TCL用,就可以寫在command內(nèi)。
?
最後,在結(jié)束這個章節(jié)前,筆者要跟大家做個經(jīng)驗的分享。在筆者使用ns2去做研究的時候,經(jīng)常會去用myfifo queue去做一些量測,例如去量測封包傳送到網(wǎng)路的時的時間、大小、或者是統(tǒng)計封包被丟棄的數(shù)量,雖然這些量測都可以使用awk去分析trace file而得到,但是要提醒大家,若是要模擬的資料太大的時候,去分析的時間也會很久,但若是直接在模組內(nèi)去撰寫量測的程式,模擬結(jié)束後,所需要的資料就已經(jīng)可以獲得了。
?
總結(jié)
以上是生活随笔為你收集整理的如何新增或修改ns2的核心模組--queue management的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 无线网络国际会议排名(zz)
- 下一篇: 关闭Windows不必要服务,电脑更安全