1. 程式人生 > >ns2模擬學習(六)-自定義協議

ns2模擬學習(六)-自定義協議

這次,我是仿照ns2中的sctp,實現了一個多宿主的UDP協議,目前還比較簡單,只能獲取端到端的rtt,能夠明顯看到資料包的亂序情況。中間遇到遇到一些小波折,記錄在此,以備後用。

在ns2目錄下增加資料夾mpudpns2,放置所有的原始檔。

除錯的log,採用的是[1],放在mpudpns2檔案下即可使用。當然這個log程式是C語言的,用在C++的環境中需要在h檔案中,增加一個巨集定義

#ifdef __cplusplus
extern "C" {
#endif

#複製原有的內容

#ifdef __cplusplus
}
#endif
定義協議標頭檔案mpudphdr.h,裡面定義個兩種資料包型別,hdr_mpudp和hdr_mpudp_ack。定義如下:
struct hdr_mpudp
{
	double timestamp;
	int flowid;
	int packetid;
    // Packet header access functions
    static int offset_;
    inline static int &offset() {
	return offset_;
    }

    inline static hdr_mpudp*access(const Packet * p) {
		return (hdr_mpudp *) p->access(offset_);
	}
};
struct hdr_mpudp_ack
{
	double timestamp;
	double mpudp_timestamp;//is the timestamp in hdr_mpudp;
	int packetid;
	int flow_id_;
    // Packet header access functions
    static int offset_;
    inline static int &offset() {
	return offset_;
    }

    inline static hdr_mpudp_ack*access(const Packet * p) {
		return (hdr_mpudp_ack *) p->access(offset_);
	}
};
在mpudp.cc檔案內定義類註冊相應的資料包頭偏移,就是Packet中的結構體中的bits_會攜帶自定義協議頭的空間,之後可以通過型別轉換,將bits_中的記憶體進行強制轉換,獲取自定義的報文頭,(hdr_mpudp *) p->access(offset_)。註冊報文頭偏移的類如下:
static class MpUdpHeaderClass:public PacketHeaderClass
{
public:
	MpUdpHeaderClass():PacketHeaderClass("PacketHeader/MpUdp",sizeof(hdr_mpudp)){
		bind_offset(&hdr_mpudp::offset_);
	}
}class_mpudp_header;
static class MpUdpAckHeaderClass:public PacketHeaderClass
{
public:
	MpUdpAckHeaderClass():PacketHeaderClass("PacketHeader/MpUdpAck",sizeof(hdr_mpudp_ack))
	{
		bind_offset(&hdr_mpudp_ack::offset_);
	}
}class_mpudpack_header;
這個時候,需要在ns-packet.tcl(在ns2.35/tcl/lib/資料夾下)指令碼中寫入相應報文頭的名字,名字與PacketHeader/MpUdp中的第二項保持一致。如果不增加這一項,根本不能在Packet中訪問自定義的資料報頭。
# Application-Layer Protocols:
	Message # a protocol to carry text messages
	Ping 	# Ping
    	PBC     # PBC
	MpUdp
	MpUdpAck

在ns-lib.tcl中仿照SCTP的處理方式,增加相應的命令處理,修改了兩處:
//ns-lib.tcl?line=1516
Simulator instproc attach-agent { node agent }
	if {[lindex [split [$agent info class] "/"] 1] == "MpUdpAgent"} {
		$agent instvar multihome_bindings_
		set binding_ {}
		set addr [$agent set agent_addr_]
		set port [$agent set agent_port_]
		lappend binding_ $addr
		lappend binding_ $port
		lappend multihome_bindings_ $binding_
	}

	
//ns-lib.tcl  
Simulator instproc connect {src dst}
    	if {[lindex [split [$src info class] "/"] 1] == "MpUdpAgent"} {
    		$self multihome-connect $src $dst
    	}

另外,需要定義資料包型別和相應的名稱
        // insert new packet types here
static const packet_t PT_MPUDP=73; //[zsy-2017]
static const packet_t PT_MPUDP_ACK=74;//[zsy-2017]
static packet_t       PT_NTYPE = 75; // This MUST be the LAST one

name_[PT_MPUDP]="MPUDP";
name_[PT_MPUDP_ACK]="MPUDP_ACK";

在Makefile.in中增加需要編譯的原始檔:

mpudpns2/log.o  mpudpns2/mpudp.o\

之後在ns-2.35檔案下執行./configure 生成makefile,執行make,編譯

最後的模擬指令碼mpudp.tcl

	set ns [new Simulator]

	set host0_core [$ns node]
	set host0_if0 [$ns node]
	set host0_if1 [$ns node]

	$host0_core color Red
	$host0_if0 color Red
	$host0_if1 color Red

	$ns multihome-add-interface $host0_core $host0_if0
	$ns multihome-add-interface $host0_core $host0_if1

    set host1_core [$ns node]
    set host1_if0 [$ns node]
    set host1_if1 [$ns node]
    $host1_core color Blue
	$ns multihome-add-interface $host1_core $host1_if0
	$ns multihome-add-interface $host1_core $host1_if1    
    set router [$ns node]
    
    $ns duplex-link $host0_if0 $router 1Mb 200ms DropTail
    $ns duplex-link $host0_if1 $router 1Mb 100ms DropTail
    
    $ns duplex-link $host1_if0 $router 2Mb 200ms DropTail
    $ns duplex-link $host1_if1 $router 2Mb 100ms DropTail
	
	set mpudp0  [new Agent/MpUdpAgent]
	
	$ns multihome-attach-agent $host0_core $mpudp0
	$mpudp0 sender_trace "mpudpsender.txt"
	
	set mpudp1 [new Agent/MpUdpAgent]
	$mpudp1 receiver_trace "mpudpreceiver.txt"
	$ns multihome-attach-agent $host1_core $mpudp1
	
	$ns connect $mpudp0 $mpudp1
    set cbr0 [new Application/Traffic/CBR]
	$cbr0 set type_ CBR  
	$cbr0 set packet_size_ 1000  
	$cbr0 set rate_ 1mb  
	$cbr0 set random_ false 
    $cbr0 attach-agent $mpudp0	

	$ns at 0.1 "$cbr0 start"
	$ns at 5.0 "$cbr0 stop"
	
	$ns run 

最後的程式碼下載[2].

接收端接收到的ack之後答應的日誌,可以明顯反映出資料包的亂序情況:

flowid packeid timerecvack  timesender timereceiver pt
1 1     0.8205     0.1080     0.4200 74
1 3     0.8365     0.1240     0.4360 74
1 5     0.8525     0.1400     0.4520 74
1 7     0.8685     0.1560     0.4680 74
1 9     0.8845     0.1720     0.4840 74
1 11     0.9005     0.1880     0.5000 74
0 0     0.9125     0.1000     0.5120 74
1 13     0.9165     0.2040     0.5160 74
0 2     0.9285     0.1160     0.5280 74
1 15     0.9325     0.2200     0.5320 74
0 4     0.9445     0.1320     0.5440 74
1 17     0.9485     0.2360     0.5480 74
0 6     0.9605     0.1480     0.5600 74
1 19     0.9645     0.2520     0.5640 74
0 8     0.9765     0.1640     0.5760 74

原有執行指令碼上的拓補:

           ~~host0_if0~~          ~~host1_if0~~
          /   (1)200ms  \        /    (3)200ms  \
host0_core               -router-                -host1_core
          \   (2)100ms  /        \    (4)100ms  /
	    ~host0_if1~~           ~host2_if1~~ 
這種方式帶來了路由上的歧義,才會導致模擬結果中一條路徑的單向時延為0.3,另一個為0.4。因此在中間增加一個router,讓host0_if0與host0_if1之間的路徑唯一確定。