用ns写的一个网络模拟
实现rdt
里面有所有源代码和文档说明
源代码在线查看: rdt-app.cc
#include "random.h" #include "rdt-app.h" // rdtApp OTcl linkage class static class rdtAppClass : public TclClass { public: rdtAppClass() : TclClass("Application/rdtApp") {} TclObject* create(int, const char*const*) { return (new rdtApp); } } class_app_rdt; // When snd_timer_ expires call rdtApp:send_rdt_pkt() void SendTimer::expire(Event*) { t_->send_rdt_pkt(); } // When ack_timer_ expires call rdtApp:send_ack_pkt() void AckTimer::expire(Event*) { t_->send_ack_pkt(); } // Constructor (also initialize instances of timers) rdtApp::rdtApp() : running_(0), snd_timer_(this), ack_timer_(this) { bind_bw("rate0_", &rate[0]); bind_bw("rate1_", &rate[1]); bind_bw("rate2_", &rate[2]); bind_bw("rate3_", &rate[3]); bind_bw("rate4_", &rate[4]); bind("pktsize_", &pktsize_); bind_bool("random_", &random_); } // OTcl command interpreter int rdtApp::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 3) { if (strcmp(argv[1], "attach-agent") == 0) { agent_ = (Agent*) TclObject::lookup(argv[2]); if (agent_ == 0) { tcl.resultf("no such agent %s", argv[2]); return(TCL_ERROR); } // Make sure the underlying agent support MM if(agent_->supportMM()) { agent_->enableMM(); } else { tcl.resultf("agent \"%s\" does not support rdt Application", argv[2]); return(TCL_ERROR); } agent_->attachApp(this); return(TCL_OK); } } return (Application::command(argc, argv)); } void rdtApp::init() { rwindow_=7; //初始化接受方窗口大小 swindow_=7; //初始化发送方窗口大小 scale_ = 0; // Start at minimum rate rseq_ = 8; // rdt sequence number (start from 8) (receiver) sseq_ = 8; // rdt sequence number (start from 8) (sender) lastack_ =8; //the seq of the last ack_pkt interval_ = (double)(pktsize_ } void rdtApp::start() { init(); running_ = 1; send_rdt_pkt(); } void rdtApp::stop() { running_ = 0; } // Send application data packet void rdtApp::send_rdt_pkt() { hdr_rdt mh_buf; if (running_) { // the below info is passed to UDPrdt agent, which will write it // to rdt header after packet creation. swindow_--; mh_buf.ack = 0; // This is not a ack packet mh_buf.rej = 0; // This is not a rej packet mh_buf.seq = ((sseq_++) % 8); // rdt sequece number mh_buf.nbytes = pktsize_; // Size of rdt packet (NOT UDP packet size) mh_buf.time = Scheduler::instance().clock(); // Current time mh_buf.scale = scale_; // Current scale value agent_->sendmsg(pktsize_, (char*) &mh_buf); // send to UDP // Reschedule the send_pkt timer double next_time_ = next_snd_time(); if(next_time_ > 0) snd_timer_.resched(next_time_); } } // Schedule next data packet transmission time double rdtApp::next_snd_time() { // Recompute interval in case rate or size chages interval_ = (double)(pktsize_ double next_time_ = interval_; if(random_) next_time_ += interval_ * Random::uniform(-0.5, 0.5); return next_time_; } // Receive message from underlying agent void rdtApp::recv_msg(int nbytes, const char *msg) { if(msg) { hdr_rdt* mh_buf = (hdr_rdt*) msg; if(mh_buf->ack == 1) { // If received packet is ACK packet adjust_swindow(mh_buf); lastack_ = mh_buf->seq; set_scale(mh_buf); } else if( mh_buf ->rej == 1) { // If received packet is REJ packet resend_rdt_pkt(mh_buf); } else { // If received packet is rdt packet account_recv_pkt(mh_buf); if(mh_buf->seq == 8) send_ack_pkt(); else if(mh_buf->seq !=((rseq_ + 1) % 8)) { send_rej_pkt(); } else { rseq_= mh_buf ->seq; rwindow_--; } } } } void rdtApp::adjust_swindow( const hdr_rdt *mh_buf) { if(swindow_ == 0) { swindow_ = swindow_ +( (mh_buf->seq + 8 - lastack_ ) % 8); send_rdt_pkt(); } else swindow_ = swindow_ +( (mh_buf->seq + 8 - lastack_ ) % 8); } void rdtApp::adjust_rwindow(void) { rwindow_ = rwindow_ + (( rseq_ - lastack_ ) % 8); } void rdtApp::resend_rdt_pkt( const hdr_rdt *mh_buf) { sseq_ =mh_buf->seq; send_rdt_pkt(); } void rdtApp::send_ack_pkt(void) { double local_time = Scheduler::instance().clock(); adjust_scale(); // send ack message hdr_rdt ack_buf; ack_buf.rej=0; ack_buf.ack = 1; // this packet is ack packet ack_buf.seq= rseq_; ack_buf.time = local_time; ack_buf.nbytes = 40; // Ack packet size is 40 Bytes ack_buf.scale = p_accnt.last_scale; adjust_rwindow(); agent_->sendmsg(ack_buf.nbytes, (char*) &ack_buf); // schedul next ACK time ack_timer_.resched(p_accnt.rtt); } void rdtApp::send_rej_pkt(void) { double local_time = Scheduler::instance().clock(); adjust_scale(); // send ack message hdr_rdt ack_buf; ack_buf.rej=1; ack_buf.seq= rseq_; ack_buf.ack = 0; // this packet is ack packet ack_buf.time = local_time; ack_buf.nbytes = 40; // Ack packet size is 40 Bytes ack_buf.scale = p_accnt.last_scale; agent_->sendmsg(ack_buf.nbytes, (char*) &ack_buf); } // Sender sets its scale to what reciver notifies void rdtApp::set_scale(const hdr_rdt *mh_buf) { scale_ = mh_buf->scale; } void rdtApp::account_recv_pkt(const hdr_rdt *mh_buf) { double local_time = Scheduler::instance().clock(); // Calculate RTT if(mh_buf->seq == 0) { init_recv_pkt_accounting(); p_accnt.rtt = 2*(local_time - mh_buf->time); } else p_accnt.rtt = 0.9 * p_accnt.rtt + 0.1 * 2*(local_time - mh_buf->time); // Count Received packets and Calculate Packet Loss p_accnt.recv_pkts ++; p_accnt.lost_pkts += (mh_buf->seq - p_accnt.last_seq - 1); p_accnt.last_seq = mh_buf->seq; } void rdtApp::init_recv_pkt_accounting() { p_accnt.last_seq = -1; p_accnt.last_scale = 0; p_accnt.lost_pkts = 0; p_accnt.recv_pkts = 0; } void rdtApp::adjust_scale(void) { if(p_accnt.recv_pkts > 0) { if(p_accnt.lost_pkts > 0) p_accnt.last_scale = (int)(p_accnt.last_scale / 2); else { p_accnt.last_scale++; if(p_accnt.last_scale > 4) p_accnt.last_scale = 4; } } p_accnt.recv_pkts = 0; p_accnt.lost_pkts = 0; }