(转)添加一个新的应用和代理(一)

  • 目标:

      建立一个影像媒体应用数据流,可以根据当前网络的拥塞状况,可以自适应的(分为 0-4, 共五个级别)调整发送的数据量的大小。

 

  • 应用描述:

      发送方与接收方,共同定义了五组(0-4) 方案,每一种方案有不同的编码与传输策略。在每一组方案和不考虑编码方案的下,传输的速率是不变的,且每个数据包的大小是固定的。

      工作方式如下:(发送方为 A,接收方为 B)

       例如:初始时,发送方 以组 方案进行发送数据,当接收方 认为网络的拥塞状况严重时,发送给 一个数据包,要求以组 方案发送数据,即是降低一倍。如果 认为网络又拥塞状况改善时,发给 一个数据包,要求以组 方案发送数据,即是提高一档。每隔一段时间,B 会发送 一个数据包,要求 以某个方案发送影像数据。

 

  • 问题分析:

      因为在实际的应用中,UDP 数据流是和应用密切相关的。我们应当让 UDP 端可以应用中 接收数据,并把数据打包,然后进行发送。而在 NS 中缺省的 UDP 只使用仅有包头的数据 包。这一点是不满足我们的要求的。所以,要对 UDP 部分进行一定的修改,让其有这个机制能够处理这个问题。

       而且,这个实验对于以后对 IP 路由排队研究的深入做一定的基础学习。这样的话,我们就要在 IP 头部分记录数据的类型。

 

  • 设计与实现:

      对于这个例子,我们修改一个 CBR 的例子使其具有 0-4 组方案的传输。

1、先构造一个 C++,MmApp,从 Application 继承而来。应用层的发送和接收均在此类 中完成

2、在 OTCL 空间中的映射为 Application/MmApp

3、在构造一个 C++类名 UdpMmAgent 从 UdpAgent 中继承,传输层的发送和接收在此类中完成。

4、在 OTCL 空间中的映射为 Agent/UDP/UDPmm

 

  • 这篇所需的文件以及文件的位置:

packet.h                                               in “ns-2.29/common/packet.h”

agent.h                                              in “ns-2.29/common/agent.h”

app.h                                                   in “ns-2.29/apps/app.h”

Makefile                                            in “ns-2.29/Makefile”

 

 

the locations of OTcl files :

ns-packet.tcl                                        in “ns-2.29/tcl/lib/ns-packet.tcl”

ns-default.tcl                                       in “ns-2.29/tcl/lib/ns-default.tcl”

 

  • 操作步骤:

  1. 准备核心代码:进入ns-2.29目录中,分别新建mm-app.cc, mm-app.h, udp-mm.cc, udp-mm.h四个文件,其代码附在文章后面。(这四个文件,读者应该认真研读,因为从这可以看应用层和代理的工作过程)

  2. packet.h文件中,增加代码,其目的是在NS中注册,把“Multimedia”加入头堆栈中。

        // Bell Labs Traffic Trace Type (PackMime OL)

static const packet_t PT_BLTRACE = 60;

 

         // Multimedia packet

         PT_Multimedia

 

       // insert new packet types here

        PT_NTYPE // This MUST be the LAST one

 

 

 

               // Bell Labs (PackMime OL)

             name_[PT_BLTRACE]="BellLabsTrace";

              name_[PT_Multimedia]="Multimedia";

              name_[PT_NTYPE]= "undefined";

 

3.将下面代码加入到“ns-packet.tcl”文件中,作用与上面是一样的:

         HDLC # High Level Data Link Control

         Multimedia #Multimedia

} {

add-packet-header $prot

}

 

 

4.修改agent.h文件

       在Class Agent 增加两个成员函数 supportMM( )和 enableMM( )来检查 Agent 是否支持 MM。在 class MmApp 中的 command 成员函数中,定义attach agent OTCL 命令。这个命令执行前,会调用 class Agent 中的成员函数 supportMM( )和 enableMM( )来检查 Agent 是否支持 MM。即使这两个成员函数在类udpMmAgent中已经定义了,但是如果在它的父类Agent中没有定义,会出现编译错误,所以要在Agent类中也要定义。

 

virtual int supportMM() { return 0; }

virtual void enableMM() {};

virtual void sendmsg(int nbytes, const char *flags = 0);

virtual void send(int nbytes) { sendmsg(nbytes); }

 

5.修改app.h文件:

     需要在Application类中增加一个成员函数 virtual void recv_msg(int nbytes,const char *msg=0){};这个函数在早期的 NS 中是有的。但是在ns-2.1b8a后的版本又被去掉了。这个要根据你具体使用的 NS 而定。

 

class Application : public Process {

public:

          Application();

          virtual void send(int nbytes);

          virtual void recv(int nbytes);

          virtual void recv_msg(int nbytes,const char *msg=0){};

          virtual void resume();

 

6.ns-default.tcl中为新参数设置指定的值:

 

Application/Traffic/CBR set rate_ 448Kb ;# corresponds to interval of 3.75ms

Application/Traffic/CBR set packetSize_ 210

Application/Traffic/CBR set random_ 0

Application/Traffic/CBR set maxpkts_ 268435456; # 0x10000000

 

Application/Telnet set interval_ 1.0

 

Application/MmApp set rate0_ 0.3mb

Application/MmApp set rate1_ 0.6mb

Application/MmApp set rate2_ 0.9mb

Application/MmApp set rate3_ 1.2mb

Application/MmApp set rate4_ 1.5mb

 

Application/MmApp set pktsize_ 1000

Application/MmApp set random_ false

 

 

7.修改Makefile文件,增加对象文件mm-app.oudp-mm.o:

 

       wpan/p802_15_4nam.o wpan/p802_15_4phy.o \

       wpan/p802_15_4sscs.o wpan/p802_15_4timer.o \

       wpan/p802_15_4trace.o wpan/p802_15_4transac.o \

      apps/pbc.o \

    ex-linkage.o \

    mm-app.o \

      udp-mm.o \

     $(OBJ_STL)

 

8.重新编译:在重新编译以前,先执行make cleanmake depend命令,否则新的应用有可能不传达任何包。

  1. ns-allinone-2.33/ns-2.33

  2. make clean

  3. make depend

  4. make

9.测试模拟.

 

下面来具体分析一下udp-mm.(h cc)和mm-app.(h cc)文件

udp-mm.h

//Author:Vivian
//File:udp-mm.h
//Written:08/25/10
//

#ifndef ns_udp_mm_h
#define ns_udp_mm_h
#include "udp.h"
#include "ip.h"


//虚拟一个多媒体应用的行为,定义多媒体报头结构
struct hdr_mm {
 
 int ack;           //判断是否为ACK包
 int seq;      //mm包的序号
 int nbytes;     //mm包的大小
 double time;    //当前时间
 int scale;     //5种不同的发送速率scale(0-4)
 //定义访问hdr_mm报头函数
 static int offset_;
 inline static int& offset() { return offset_; }
  inline static hdr_mm* access(const Packet* p) {
                return (hdr_mm*) p->access(offset_);
 }
};

//mm报的重组
struct asm_mm {
 int seq;     //mm报序号
 int rbytes;    //当前收到的bytes
 int tbytes;    //收到的所有mm报的总的大小
};

//UdpMmAgent类的定义
class UdpMmAgent : public UdpAgent {
public:
 UdpMmAgent();
 UdpMmAgent(packet_t);  //两个构造函数
 virtual int supportMM() {return 1;}  //判断是否为mm报
 virtual void enableMM() {support_mm_ = 1;}
 virtual void sendmsg(int nbytes,const char* flags = 0);
 void recv(Packet*,Handler*);
protected:
 int support_mm_;   //如果是mm报,则赋值1
private:
 asm_mm asm_info;   //报重组信息
};

#endif
 这个头文件比较简单,定义了一个multimedia的新的报头格式,并定义了一个偏移地址用于访问hdr_mm。而UdpMmAgent类继承了UdpAgent 。里面有supportMM()意为判断是否为MM包,如果支持则执行enableMM()。sendmsg()函数用来对数据进行判断、分割和发送。recv()函数用来接收从底层上来的包。这里UdpMmAgent扩展了原始的UdpAgent 的功能。添加了重组的方法。

udp-mm.cc

1、static class MultimediaHeaderClass : public PacketHeaderClass {
public:
 MultimediaHeaderClass() : PacketHeaderClass("PacketHeader/Multimedia",sizeof(hdr_mm)) {
  bind_offset(&hdr_mm::offset_);
 }
} class_mmhdr;

static class UdpMmAgentClass : public TclClass {
public:
 UdpMmAgentClass() : TclClass("Agent/UDP/UDPmm") {}
 TclObject* create(int,const char*const*) {
  return (new UdpMmAgent());
 }
}class_udpmm_agent;

//构造函数
UdpMmAgent::UdpMmAgent() : UdpAgent()
{
 support_mm_ = 0;
 asm_info.seq = -1;
}

//构造函数,含参数
UdpMmAgent::UdpMmAgent(packet_t type) : UdpAgent(type)
{
 support_mm_ = 0;
 asm_info.seq = -1;
}
 片段1主要定义了对 MultimediaHeaderClass到PacketHeaderClass 的映射类,并指定报头名称为Multimedia。注意其中一定要对hdr_mm报头的便宜地址进行绑定。之后定义了对UdpMmAgentClass到TclClass的映射类,并制定名称为UDPmm。

 

2、

//添加对多媒体应用的支持到UdpAgent::sendmsg
void UdpMmAgent::sendmsg(int nbytes,const char* flags)
{
  Packet* p;
  int n,remain;
  
  if(size_) {
   n = (nbytes/size_ + (nbytes%size_ ? 1 : 0));
    remain = nbytes%size_;
  }
  else
   printf("Error: UDPmm size=0\n");
   
  if (nbytes == -1) {
   printf("Error: sendmsg() for UDPmm should not be -1\n");
   return;
  }
  double local_time = Scheduler::instance().clock();
  while (n-- > 0) {
   p = allocpkt();
   if (n==0 && remain>0) hdr_cmn::access(p)->size() = remain;
   else hdr_cmn::access(p)->size() = size_;
   hdr_rtp* rh = hdr_rtp::access(p);
   rh->flags() = 0;
   rh-> seqno() = ++seqno_;
   hdr_cmn::access(p)->timestamp() = (u_int32_t)(SAMPLERATE* local_time);
   //to eliminate recv to use MM fields for non MM packets 对于非MM包,清除MM参数
   hdr_mm* mh = hdr_mm::access(p);
   mh->ack = 0;
   mh->seq = 0;
   mh->nbytes = 0;
   mh->time = 0;
   mh->scale = 0;
   //mm udp packets are distinguished by setting the ip
   //priority bit to 15
   if(support_mm_) {
    hdr_ip* ih = hdr_ip::access(p);
    ih->prio_ = 15;
    if(flags) //MM Seq Num is passed as flags
     memcpy(mh, flags, sizeof(hdr_mm));  //把flags首地址开始,长度为hdr_mm的内容复制到mh中
    }
    if (flags && (0 == strcmp(flags,"NEW_BURST")))
     rh->flags() |= RTP_M;
    target_->recv(p);
   }
   idle();
}

 这里和原始的UDPAgent中sendmsg十分相似,只不过多了

 if(size_) {
   n = (nbytes/size_ + (nbytes%size_ ? 1 : 0));
    remain = nbytes%size_;
  }
这段函数实现了对接收到的数据包进行分割和发送。

3、

void UdpMmAgent::recv(Packet* p,Handler*)
{
 hdr_ip* ih = hdr_ip::access(p);
 int bytes_to_deliver = hdr_cmn::access(p)->size();
 //如果是一个MM包
 if(ih->prio_ == 15) {
  if(app_) { //如果MM应用存在,当MM 包被分割后进行重组
   hdr_mm* mh = hdr_mm::access(p);
   if(mh->seq == asm_info.seq)
    asm_info.rbytes += hdr_cmn::access(p)->size();
   else {
    asm_info.seq = mh->seq;
    asm_info.tbytes = mh->nbytes;
    asm_info.rbytes = hdr_cmn::access(p)->size();
   }
   //如果完全重组好了,将包传递到应用层
   if(asm_info.tbytes == asm_info.rbytes) {
    hdr_mm mh_buf;
    memcpy(&mh_buf,mh,sizeof(hdr_mm));
    app_->recv_msg(mh_buf.nbytes,(char*) &mh_buf);
   }
  }
  Packet::free(p);
 }
 //如果是个普通的包
 else {
  if (app_) app_->recv(bytes_to_deliver);
   Packet::free(p);
 }
}

这段函数实现对接收到的MM包进行重组。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值