參考資料:http://blog.csdn.net/leo115/article/details/7784349
徐雷鳴:NS與網路類比
MFlood類中有recv函數
先檢測是否是自己產生的,如果是自己發的,且轉寄的次數為0,那麼就是自己產生的。
ip header的source addr,index_是自己的ip地址,比較這兩個可以判斷是否自己發的
common header中的num_forwards可以得到轉寄的次數
如果是自己產生的將common header的size加上IP包的長度,將ip header的ttl設為最大,將flood的seq_加1,然後轉寄包。
然後檢測是否是路由環路,如果是自己發的,且轉寄次數不為0,那麼就是一個路由環路,丟棄
然後檢測ttl是否為0,如果是丟棄
如果不是上面所有的情況,那麼解析包,即尋找下一跳地址。
// Packet Reception RoutinesvoidMFlood::recv(Packet *p, Handler*) {struct hdr_cmn *ch = HDR_CMN(p);struct hdr_ip *ih = HDR_IP(p);struct hdr_mflood *fh = HDR_MFLOOD(p);assert(initialized());if((ih->saddr() == index_) && (ch->num_forwards() == 0)) {// Must be a packet I'm originating...ch->size() += IP_HDR_LEN;// Add the IP Headerih->ttl_ = NETWORK_DIAMETER;fh->seq_ = myseq_++;forward((MFlood_RTEntry*)1,p,0);return;} else if(ih->saddr() == index_) {// I received a packet that I sent. Probably a routing loop.drop(p, DROP_RTR_ROUTE_LOOP);return;} else {// Packet I'm forwarding...if(--ih->ttl_ == 0) {// Check the TTL. If it is zero, then discard.drop(p, DROP_RTR_TTL); return;}}rt_resolve(p);}
路由表解析,先檢查路由表項中有沒有這個源地址(路由表項裡不是目的地址嗎?因為是擴散法,見電腦網路書,或下面對seqno的解釋),如果沒有,那麼需要建立這個路由表項,並將其插入路由表的路由表項鏈表,路由表是表(程式中實際實現是通過鏈表實現,而不是二維數組什麼的,因為二維數組刪除添加什麼的不靈活),路由表項是路由表的元素,Entry是表項的意思。添加完路由表項之後,再轉寄。
// Route Handling FunctionsvoidMFlood::rt_resolve(Packet *p) {struct hdr_cmn *ch = HDR_CMN(p);struct hdr_ip *ih = HDR_IP(p);struct hdr_mflood *fh = HDR_MFLOOD(p);MFlood_RTEntry* rt;rt = rtable_.rt_lookup(ih->saddr());if(rt == NULL) {rt = new MFlood_RTEntry(ih->saddr(), fh->seq_);LIST_INSERT_HEAD(&rtable_.rthead,rt,rt_link);//printf("%.8f %d,no uptarget,\n",NOW,index_);forward(rt,p,FORWARD_DELAY);//printf("%.8f %d,no rt,so forward.rt_seq:%d,pkt seq:%d\n",NOW,index_,rt->max_seqno,fh->seq_);rtable_.rt_print();}//else if(rt->seq_ < fh->seq_ )else if(rt->isNewSeq(fh->seq_) ){
如果路由表項中有這個源地址,再檢查seq是否重複,使用了max_seqno, min_seqno,在一個數組中儲存已經接收到的seqno。如果不重複,那麼轉寄,同時將seqno添加進路由表項中。
電腦網路書中對flood擴散法的說明:每個源路由器(在這裡為源節點,因為WSN中節點也充當路由器的角色)對從自己產生的分組維護一個序號seqno,中間的路由器針對每個源地址都儲存一個seqno表,從而判斷是否是重複包。所以,路由表項中的地址是源地址,而不是普通路由演算法的目的地址。
else if(rt->isNewSeq(fh->seq_) ){//printf("%.8f %d,no uptarget,\n",NOW,index_);forward(rt, p, FORWARD_DELAY);//rt->seq_ = fh->seq_;rt->addSeq(fh->seq_);//printf("%.8f %d,rt seq too small,so forward,rt_seq:%d,packet seq:%d.\n",NOW,index_,rt->max_seqno,fh->seq_);rtable_.rt_print();}else{drop(p, "LOWSEQ");}}
下面解釋一下整個路由表的實現,發現自己背離了擴散法的原理去讀代碼,結果讀的一頭霧水,當重新瞭解了一下擴散法的原理之後,代碼也就清晰了,汗顏啊!而且,徐雷鳴的書中有專門介紹MFlood的,裡面也講的比較清楚,早看的話,就能少走些彎路了,不過自己想出來的也挺有成就感的:
MFlood類下會有路由表rtable_,而路由表類下又有一個路由錶鏈表(由路由表項元素組成的鏈表)rthead,而路由表項類下會有變數src_,這就是源地址,每個表項對應一個源地址,對應一個序號seqno數組rt_seqnos[REM_SEQ_COUNT]。
即每個路由表項下會有一個源地址,一個序號數組,這就是擴散法的路由表需要的內容,而普通路由演算法的話,應該會有目的地址,下一跳地址等。
另外為了防止路由表項無限擴大,設定了max_seqno變數(電腦網路書中講到),如果收到的分組的源地址對應的seqno大於max,那麼肯定是新的;如果小於max,mflood中還設定了一個min_seqno,用於丟棄太久之前的包,這裡可能seqno回卷的話就不對了啊,這裡每太想明白???
關於路由表項鏈表的操作也沒太看明白,下面這個鏈表表項第二項是上一個下一個元素的地址,鏈表不是上一個元素和下一個元素的指標嗎???
#define LIST_ENTRY(type) \struct { \ type*le_next; /* next element */ \ type**le_prev; /* address of previous nextelement */ \}
一開始一直看不明白下面是什麼意思,怎麼還把基類的建構函式搬出來了,C++繼承那塊一直沒仔細看,原來繼承不會繼承基類的構造和解構函式,在衍生類別建構函式時,也要執行基類的建構函式,當衍生類別中內嵌其他類的時候,也要將這些類構造。
MFlood::MFlood(nsaddr_t id) : Agent(PT_MFLOOD) {index_ = id;logtarget = 0;myseq_ = 0;}
徐雷鳴書中對C++和Tcl之間關係的解釋: