zoukankan      html  css  js  c++  java
  • 在NS2中添加一个新的协议

    简介:
    在NS中添加一个新的网络元素通常都需要是Otcl 链接到C++类。在NS2中的元素的实现都是用C++编写的主要是出于执行效率的考虑。在这篇文章中会介绍在NS2中添加一个新的元素来理解C++/OTcl是如何链接的。在这篇文章中我们用以个新的简单的协议“MyAgent”,这个协议没有具体的方法。

    1.扩展C++类到OTcl
    假设你已经新建了一个C++类,在这篇文章中叫“MyAgent”,它是从“Agent”类继承而来的,你当然想通过OTcl中创建一个“MyAgent”的实例对象,这就需要定义一个链接类,在这儿我们叫做“MyAgentClass”,它是从”TclClass“中继承而来的。这个链接类的对象创建一个OTcl名为“Agent/MyAgentOtcl”对象,同时注册了OTcl对象和C++对象的对应关系。见下面的代码:

    class MyAgent : public Agent { 
    public: 
    MyAgent(); 
    protected: 
    int command(int argc, const char*const* argv); 
    private: 
    int    my_var1; 
    double my_var2; 
    void   MyPrivFunc(void); 
    }; 


    static class MyAgentClass : public TclClass { 
    public: 
    MyAgentClass() : TclClass("Agent/MyAgentOtcl") {} 
    TclObject* create(int, const char*const*) { 
    return(new MyAgent()); 

    } class_my_agent; 

    当NS 最开始启动时,它就会执行这个静态变量“class_my_agent”的构造函数,从而使“MyAgentClass”实例化了一个对象。在这个过程中,在OTcl的空间中同时也创建了一个名字为“Agent/MyAgentOtcl”的类。不论何时当一个用户在OTcl中用命令“new Agent/MyAgentOtcl”就会创建一个这个类的对象,它同时也会引发“MyAgentClass::create”创建一个“MyAgent”的实例并且返回一个地址(这个地址是保存在Tcl类中的哈希表中的)。值得注意的是能够通过OTcl创建一个C++对象并不意为这你可以在OTcl中访问它的属性和方法。这个问题我们会在下面的内容中解决。

    2.扩展C++类中的属性到OTcl
    在上面所建的“MyAgent”类中,有两个属性“my_var1”和“my_var2”,当然我们想在OTcl中通过仿真脚本能够很轻松的配置他们。为了做到这个,你就应该为每个你想要扩展的属性用binding函数。这个binding函数会在OTcl中对应的类(这儿是“Agent/MyAgentOtcl”)中创建一个名字为binding函数第一个参数的值的成员变量,同时会把C++中的变量的地址(binding函数的第二个参数)和这个变量绑定起来。见下面的代码:

    MyAgent::MyAgent() : Agent(PT_UDP) { 
    bind("my_var1_otcl", &my_var1); 
    bind("my_var2_otcl", &my_var2); 


    注意binding函数是在“MyAgent”类的构造函数中调用的,NS支持四种不同的类型的绑定(因为C++是一个强类型的语言而Tcl中只有字符串一种类型,这就需要一个转换)。

    a. bind(): 绑定整型和实数类型的变量
    b. bind_time(): 绑定时间变量
    c. bind_bw(): 绑定带宽变量
    d. bind_bool(): 绑定boolean变量

    通过上述方法,用户就可以通过OTcl脚本来改变用C++编写的网络元素的属性的值。值得注意的是,当你想要扩展一个C++变量是,希望你能够在“~ns/tcl/lib/ns-default.tcl”中设定这个变量的初始值,否则你会在创建一个对象的时候收到警告信息。

    3.扩展C++类的方法到Otcl
    除了扩展一些C++属性之外,你也许会想通过OTcl来实现C++类中的方法。这时你需要在你的C++类“MyAgent”增加一个名为“command”的函数,这个函数就像是OTcl命令的一个解释器。实际上,一个在“command”中定义的OTcl命令就像是OTcl对象种的成员函数。见如下代码:

    int MyAgent::command(int argc, const char*const* argv) { 
    if(argc == 2) { 
    if(strcmp(argv[1], "call-my-priv-func") == 0) { 
    MyPrivFunc(); 
    return(TCL_OK); 


    return(Agent::command(argc, argv)); 


    当在OTcl中一个名为“MyAgent”类的影像对象被创建时,用户试图通过一些命令来调用改影像对象的方法($myagent call-my-priv-func),OTcl就会会寻找在OTcl对象种的call-my-priv-func实例过程。如果这个过程没有被找到,这个时候就会触发“MyAgent::command”函数的执行,这个函数的参数是从OTcl对象以argc/argv的形式获得的。如果找到了这个命令,那就回去执行这个命令并从中返回一个结果。
    如果没有找到相应的命令,那么就会递归的去调用”MyAgent“父类的“command”函数。如果在它的父类中找到相应的命令则执行,否则继续向上找,如果没有找到那么就返回错误消息。

    4.在C++中执行OTcl命令
    当你想在C++中执行OTcl命令时,下面的代码给出了如果在“MyPrivFunc”中执行OTcl命令:

    void MyAgent::MyPrivFunc(void) { 
    Tcl& tcl = Tcl::instance(); 
    tcl.eval("puts \"Message From MyPrivFunc\""); 
    tcl.evalf("puts \"     my_var1 = %d\"", my_var1); 
    tcl.evalf("puts \"     my_var2 = %f\"", my_var2); 
    }

    为了能够在C++中执行OTcl命令,你需要通过“Tcl::instance()"得到一个Tcl实例的引用(去阅读Tcl类的源代码你会发现这个实例是个静态变量)。它就相当于提供了OTcl命令的解释器的接口。

    5.编译,运行和测试”MyAgent“

    a.把你写好的代码添加到ns安装目录下的ns目录下,最好是建立一个自己的文件夹
    b.修改ns下的Makefile,把你要编译的文件加进去
    c.重新编译你的NS,使用”make“命令
    d.编写仿真Tcl文件
    e.执行你的仿真Tcl文件

    附C++代码和Tcl代码:

    #include <stdio.h> 
    #include <string.h> 
    #include "agent.h" 


    class MyAgent : public Agent { 
    public: 
    MyAgent(); 
    protected: 
    int command(int argc, const char*const* argv); 
    private: 
    int    my_var1; 
    double my_var2; 
    void   MyPrivFunc(void); 
    }; 


    static class MyAgentClass : public TclClass { 
    public: 
    MyAgentClass() : TclClass("Agent/MyAgentOtcl") {} 
    TclObject* create(int, const char*const*) { 
    return(new MyAgent()); 

    } class_my_agent; 


    MyAgent::MyAgent() : Agent(PT_UDP) { 
    bind("my_var1_otcl", &my_var1); 
    bind("my_var2_otcl", &my_var2); 



    int MyAgent::command(int argc, const char*const* argv) { 
    if(argc == 2) { 
    if(strcmp(argv[1], "call-my-priv-func") == 0) { 
    MyPrivFunc(); 
    return(TCL_OK); 


    return(Agent::command(argc, argv)); 



    void MyAgent::MyPrivFunc(void) { 
    Tcl& tcl = Tcl::instance(); 
    tcl.eval("puts \"Message From MyPrivFunc\""); 
    tcl.evalf("puts \"     my_var1 = %d\"", my_var1); 
    tcl.evalf("puts \"     my_var2 = %f\"", my_var2); 


    -----------------------end C++ code ---------------------------------

    set myagent [new Agent/MyAgentOtcl]

    # Set configurable parameters of MyAgent
    $myagent set my_var1_otcl 2
    $myagent set my_var2_otcl 3.14

    # Give a command to MyAgent
    $myagent call-my-priv-func

    ------------------------end Tcl code------------------------------------
  • 相关阅读:
    Redis安装-Redis常用命令-redis.conf配置信息总结
    JVM--心得 OOM时的堆信息获取与分析
    JVM--心得 堆栈区域和GC的设置
    JVM--心得(加载 链接 初始化)
    JVM--心得概念
    我的Python之路:找一个幸运数
    springboot模板
    spring boot入门
    java自定义注解
    git集成idea
  • 原文地址:https://www.cnblogs.com/gxwang/p/4940876.html
Copyright © 2011-2022 走看看