这次,我是仿照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之间的路径唯一确定。
[1]rxc/log.c
[2]ns2自定义协议下载