mptcp实现学习——mpTopology.cc阅读

/*CS740 Project by Yilong Li and Chuhan Gao

NS-3 Simulation of MPTCP(Multiplr Path TCP) in 802.11ad WiGig and WiFi.

Two subflows work on Wi-Fi band(500MHz Bandwidth) and 60Ghz 802.11ad(2000MHz Bandwidth) seperately.
这个代码是一个关于 MPTCP 在 802.11ad WiGig 和 WiFi 环境中的 NS-3 仿真项目。
代码中包含两个子流,分别在 Wi-Fi 和 60GHz 802.11ad 上工作
根据代码的实现,这段代码使用了多路径传输协议(Multipath TCP,简称MPTCP),其中涉及了拥塞控制算法和数据包重排序算法。拥塞控制算法通过设置lSocket->SetCongestionCtrlAlgo来选择,目前是使用了Uncoupled_TCPs,即不同的子流(subflow)之间相互独立进行拥塞控制。
数据包重排序算法通过设置lSocket->SetPacketReorderAlgo来选择,目前是使用了D_SACK,即基于选择确认(Selective Acknowledgment,简称SACK)的数据包重排序。因此,这段代码中对拥塞控制和数据包重排序进行了处理,以提高多路径传输的性能和可靠性。
 在这段代码中,拥塞控制算法和数据包重排序算法的设置分别发生在以下两个地方:

在StartFlow函数中,通过调用lSocket->SetCongestionCtrlAlgo设置拥塞控制算法,目前设置为Uncoupled_TCPs。这个函数是在建立连接后开始数据传输之前调用的。
在StartFlow函数中,通过调用lSocket->SetPacketReorderAlgo设置数据包重排序算法,目前设置为D_SACK。这个函数也是在建立连接后开始数据传输之前调用的。

根据代码中的设置,这段代码使用的是非耦合的拥塞控制算法。
在StartFlow函数中,通过调用lSocket->SetCongestionCtrlAlgo来设置拥塞控制算法,目前设置为Uncoupled_TCPs,即不同子流(subflow)之间相互独立进行拥塞控制。这意味着每个子流都维护自己的拥塞窗口和拥塞控制算法状态,并独立地进行拥塞控制,而不考虑其他子流的拥塞状况。
耦合的拥塞控制算法(Coupled Congestion Control)则是指多个子流共享一个拥塞控制状态,它们共同决定拥塞窗口大小和拥塞控制策略。
耦合的拥塞控制算法可以更好地利用网络资源,但也需要更复杂的协调和控制。
*/

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <stdint.h>


#include "ns3/core-module.h"
//#include "ns3/simulator-module.h"
//#include "ns3/node-module.h"
//#include "ns3/helper-module.h"
#include "ns3/wifi-module.h"
#include "ns3/mobility-module.h"

#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"

#include "ns3/mp-tcp-typedefs.h"
#include "ns3/mp-internet-stack-helper.h"
#include "ns3/mp-tcp-packet-sink.h"
#include "ns3/mp-tcp-l4-protocol.h"
#include "ns3/mp-tcp-socket-base.h"
#include "ns3/mp-tcp-packet-sink-helper.h"
#include "ns3/point-to-point-channel.h"
#include "ns3/point-to-point-net-device.h"
#include "ns3/log.h"
#include "ns3/proprietary-tracing.h"
//包含一系列 NS-3 模块的头文件,这些模块用于网络仿真和模拟实验。
/* 
#include <iostream>:包含输入输出流的头文件,用于在代码中使用输入和输出功能。

#include <sstream>:包含字符串流的头文件,用于在代码中对字符串进行流式处理。

#include <string>:包含字符串处理的头文件,用于在代码中进行字符串操作。

#include <vector>:包含向量容器的头文件,用于在代码中使用向量容器。

#include <stdint.h>:包含整数类型的头文件,用于在代码中使用特定大小的整数类型。

接下来是一系列的NS-3模块的头文件引用,这些模块提供了不同的网络功能和组件:

#include "ns3/core-module.h":引用NS-3核心模块的头文件,提供了NS-3的核心功能和类。

#include "ns3/wifi-module.h":引用NS-3 Wi-Fi模块的头文件,提供了在NS-3中模拟Wi-Fi网络的功能。

#include "ns3/mobility-module.h":引用NS-3移动性模块的头文件,提供了在NS-3中模拟节点移动性的功能。

#include "ns3/network-module.h":引用NS-3网络模块的头文件,提供了在NS-3中模拟网络的功能。

#include "ns3/internet-module.h":引用NS-3 Internet模块的头文件,提供了在NS-3中模拟Internet协议的功能。

#include "ns3/point-to-point-module.h":引用NS-3点对点模块的头文件,提供了在NS-3中模拟点对点连接的功能。

#include "ns3/applications-module.h":引用NS-3应用程序模块的头文件,提供了在NS-3中模拟应用程序的功能。

接下来是一系列与MPTCP相关的头文件的引用:

#include "ns3/mp-tcp-typedefs.h":引用NS-3 MPTCP的类型定义的头文件。

#include "ns3/mp-internet-stack-helper.h":引用NS-3 MPTCP网络堆栈助手的头文件。

#include "ns3/mp-tcp-packet-sink.h":引用NS-3 MPTCP数据包接收器的头文件。

#include "ns3/mp-tcp-l4-protocol.h":引用NS-3 MPTCP L4协议的头文件。

#include "ns3/mp-tcp-socket-base.h":引用NS-3 MPTCP套接字基类的头文件。

#include "ns3/mp-tcp-packet-sink-helper.h":引用NS-3 MPTCP数据包接收器助手的头文件。

最后是一些其他的头文件引用:

#include "ns3/point-to-point-channel.h":引用NS-3点对点信道的头文件。

#include "ns3/point-to-point-net-device.h":引用NS-3点对点网络设备的头文件。

#include "ns3/log.h":引用NS-3日志库的头文件。

#include "ns3/proprietary-tracing.h":引用NS-3专有跟踪的头文件。

这些头文件的引用将提供所需的类和功能,以便在主函数中使用它们来创建网络拓扑、安装协议栈、创建MPTCP连接和应用程序,并启动模拟器。
Multipath Network Topology

     lan 10.1.1.0
      ___________
     /           \
   n1             n2
     \___________/

     lan 10.1.2.0
"10.1.3.0" 也是一个 IPv4 地址,它表示了一个局域网的网络地址。IP 地址通常由网络标识符和主机标识符组成,网络标识符指示了IP地址所在的网络,而主机标识符则指示了特定主机的地址。

在这个代码中,"10.1.3.0" 可以被看作是一个网络的起始地址,表示这个局域网中的第一个主机。通过递增主机标识符,可以将不同的主机地址分配给该网络中的不同主机。

需要注意的是,这段代码中可能还有其他类似的 IP 地址,如 “10.1.1.0” 和 "10.1.2.0",它们可能表示同一个局域网中的不同子网或其他网络。
*/

using namespace ns3;//使用 using 声明命名空间为 ns3这样我们就可以直接使用NS-3库中的函数和类,而无需使用命名空间前缀。

NS_LOG_COMPONENT_DEFINE("FirstMultipathToplogy");
//NS_LOG_COMPONENT_DEFINE 定义日志组件名称为 "FirstMultipathToplogy"。
// The number of bytes to send in this simulation.
static const uint32_t totalTxBytes = 0xFFFFFFFF;
static const uint32_t sendBufSize  = 180000; //2000000;
static const uint32_t recvBufSize  = 100000; //2000000;
static uint32_t currentTxBytes     = 0;
static const double simDuration    = 100.0;
//定义了一些用于模拟的参数和变量,
//如要发送的字节数、发送缓冲区大小、接收缓冲区大小、当前已发送的字节数和模拟时间的持续时间。
Ptr<Node> client;
Ptr<Node> server;
//定义了两个节点的指针,用于创建 NS-3 中的节点。

// Perform series of 1040 byte writes (this is a multiple of 26 since
// we want to detect data splicing in the output stream)
static const uint32_t writeSize = 1500;//sendBufSize;
uint8_t data[writeSize];
Ptr<MpTcpSocketBase> lSocket    = 0;
/*
PointToPointHelper fstP2Plink;
PointToPointHelper sndP2Plink;
PointToPointHelper trdP2Plink;
*/

void StartFlow (Ptr<MpTcpSocketBase>, Ipv4Address, uint16_t);
void WriteUntilBufferFull (Ptr<Socket>, unsigned int);
void connectionSucceeded(Ptr<Socket>);
void connectionFailed(Ptr<Socket>);

void HandlePeerClose (Ptr<Socket>);
void HandlePeerError (Ptr<Socket>);
void CloseConnection (Ptr<Socket>);
//声明了两个辅助函数的原型。
int connect(Address &addr);
void variateDelay(PointToPointHelper P2Plink);

//static void
//CwndTracer (double oldval, double newval)
//{
//  NS_LOG_INFO ("Moving cwnd from " << oldval << " to " << newval);
//}


int main(int argc, char *argv[])
{//解析命令行参数,指定了一些选项和参数的值。定义了主函数,接受命令行参数作为输入。
/*通过调用cmd.AddValue()方法,将命令行参数的名称、描述和对应的变量进行绑定。其中,命令行参数名称作为第一个参数,描述作为第二个参数,对应的变量作为第三个参数。
以下是每个命令行参数的描述信息:
verbose:告诉应用程序在日志记录时是否启用详细模式。
level:告诉应用程序要使用的日志级别。提供了以下选择:
0 = ERROR  1 = WARN  2 = DEBUG  3 = INFO  4 = FUNCTION  5 = LOGIC  6 = ALL
cc:告诉应用程序要使用的拥塞控制算法。提供了以下选择:
0 = Uncoupled_TCPs  1 = Linked_Increases  2 = RTT_Compensator  3 = Fully_Coupled
pr:告诉应用程序要使用的包重新排序算法。提供了以下选择:
0 = NoPR_Algo  1 = Eifel  2 = TCP_DOOR  3 = D_SACK  4 = F_RTO
sf:告诉应用程序要建立的子流个数。*/
  bool verbose;
  CongestionCtrl_t cc = Fully_Coupled;
  PacketReorder_t  pr = D_SACK;
  int arg1 = -1, arg2 = -1, arg3 = -1, arg4 = -1;
	 int sf = 2; // number of subflows
	  CommandLine cmd;//创建一个CommandLine对象,用于处理命令行参数。

  cmd.AddValue("verbose", "Tell application to log if true", verbose);
  cmd.AddValue("level", "Tell application which log level to use:\n \t - 0 = ERROR \n \t - 1 = WARN \n \t - 2 = DEBUG \n \t - 3 = INFO \n \t - 4 = FUNCTION \n \t - 5 = LOGIC \n \t - 6 = ALL", arg3);
  cmd.AddValue("cc", "Tell application which congestion control algorithm to use:\n \t - 0 = Uncoupled_TCPs \n \t - 1 = Linked_Increases \n \t - 2 = RTT_Compensator \n \t - 3 = Fully_Coupled", arg1);
  cmd.AddValue("pr", "Tell application which packet reordering algorithm to use:\n \t - 0 = NoPR_Algo \n \t - 1 = Eifel \n \t - 2 = TCP_DOOR \n \t - 3 = D_SACK \n \t - 4 = F_RTO",  arg2);
  cmd.AddValue("sf", "Tell application the number of subflows to be established between endpoints",  arg4);

  cmd.Parse (argc, argv);//解析命令行参数,将其应用于CommandLine对象。

  cc = (arg1==-1 ? Fully_Coupled:(CongestionCtrl_t) arg1);
  pr = (arg2==-1 ? D_SACK:(PacketReorder_t) arg2);

  /*些代码被注释掉了,它们可能是用于开发和调试过程中临时启用日志输出的方式。*/
  // sf = (arg4 = -1 ? 2: arg4);
//这行代码是一个三元运算符,根据 arg4 的值来设置 sf 的值。如果 arg4 的值为 -1,则将 sf 设置为 2,否则将 sf 设置为 arg4 的值。
//如果想要使用耦合的拥塞控制算法,可以取消以下代码段的注释:
/*这些注释掉的代码行用于启用特定组件的日志记录,包括拥塞控制算法、TCP协议、网络协议等。取消注释后,可以通过日志来跟踪耦合的拥塞控制算法的行为和状态。请注意,在取消注释之前,请确保已经在代码中包含了相应的头文件。*/
//  LogComponentEnable("FirstMultipathToplogy", LOG_LEVEL_ALL);
//  LogComponentEnable("MpTcpSocketBase", LOG_LEVEL_ALL);
//  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
//  LogComponentEnable("Icmpv6L4Protocol", LOG_LEVEL_ALL);
//  LogComponentEnable("Icmpv4L4Protocol", LOG_LEVEL_ALL);
//  LogComponentEnable("MpTcpL4Protocol", LOG_LEVEL_ALL);
//  LogComponentEnable("TcpL4Protocol", LOG_LEVEL_ALL);
//  LogComponentEnable("Packet", LOG_LEVEL_ALL);
//  LogComponentEnable("Socket", LOG_LEVEL_ALL);
//  LogComponentEnable ("PointToPointNetDevice", LOG_ALL);
//  LogComponentEnable ("MpTcpHeader", LOG_WARN);
//  LogComponentEnable ("MpTcpL4Protocol", LOG_ALL);
//  LogComponentEnable("Simulator",LOG_LEVEL_ALL);
//  LogComponentEnable("TcpHeader", LOG_LEVEL_ALL);
//  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
//  LogComponentEnable("MpTcpTypeDefs", LOG_LEVEL_ALL);
//  LogComponentEnable("RttEstimator", LOG_LEVEL_ALL);
   // LogComponentEnable("MpTcpSocketBase", LOG_LEVEL_INFO);
//这些行代码是用于启用不同模块的日志输出,并设置日志级别。
//通过指定模块的名称和日志级别,可以控制哪些日志将被输出。这些代码行中的模块名称包括 “FirstMultipathToplogy"、"MpTcpSocketBase"、"Ipv4L3Protocol"、"Icmpv6L4Protocol"、"Icmpv4L4Protocol"、"MpTcpL4Protocol"、"TcpL4Protocol"、"Packet"、"Socket"、"PointToPointNetDevice"、"MpTcpHeader"、"Simulator"、"TcpHeader"、"Ipv4L3Protocol"、"MpTcpTypeDefs” 和 "RttEstimator"。

//每一行中的 LOG_LEVEL_ALL 或 LOG_LEVEL_INFO 表示将所有日志输出都启用,而 LOG_WARN 表示只输出警告级别的日志。


//使用循环填充字符数组 data,使其包含一系列连续的小写字母。writeSize 控制了要填充的元素数量。
  for(uint32_t i = 0; i < writeSize; ++i)
    {
      char m = toascii (97 + i % 26);
      //97 + i % 26 会生成 97 到 122 之间的整数。
      //这个范围对应于小写字母 a 到 z 的 ASCII 值。
      //i % 26 的目的是在每次循环迭代中循环使用这些整数,以便填充整个字符数组。
      data[i] = m;
    }

    //创建了 ProprietaryTracing 对象,并打开用于跟踪的文件。
  	Ptr<ProprietaryTracing> pTracing=CreateObject<ProprietaryTracing> ();
  	string fileName="mpTopology-traces.tr";
	//char buf[FILENAME_MAX];
	//string path = string (getcwd(buf, FILENAME_MAX)) + "/traces/" + fileName;
	//printf("%s\n",path.c_str());
  	pTracing->OpenMpTcpTraceFile(fileName);
	string cwndtracefile="cwnd.tr";
	pTracing->OpenMpTcpWindowTraceFile(cwndtracefile);

    //创建了两个节点(主机)。
    // Creation of the hosts
    NodeContainer nodes;
    nodes.Create(2);
    client = nodes.Get(0);
    server = nodes.Get(1);
    //创建了网络堆栈和 TCP 协议栈,并将其安装到节点中。
    /*网络堆栈是一个软件模块,用于处理网络通信的各个层级。
    它负责处理网络协议、数据包的传输和路由、错误检测和校正等功能。网络堆栈通常由多个协议栈组成,其中最常见的是 TCP/IP 协议栈。

    TCP 协议栈是网络堆栈中的一个重要组成部分,负责处理传输控制协议(TCP)相关的功能。
    TCP 是一种可靠的、面向连接的协议,用于在网络上可靠地传输数据。TCP 协议栈实现了 TCP 协议的各种功能,包括连接建立、数据分段和重组、流量控制、拥塞控制等。
    将网络堆栈和 TCP 协议栈安装到节点中的目的是为了使节点能够进行网络通信。
    通过在节点上安装网络堆栈和 TCP 协议栈,节点可以与其他网络上的节点进行通信,发送和接收数据。这对于构建和实现各种网络应用和服务是必要的。
    在计算机网络中,节点可以是计算机、服务器、路由器或其他网络设备。通过安装网络堆栈和 TCP 协议栈,这些节点能够参与网络通信,并遵循 TCP/IP 协议栈的规范进行数据传输。*/
    uint32_t queueSize=5;

/*使用 MpInternetStackHelper 对象来安装多路复用(Multipath)网络堆栈到给定的节点集合中。
MpInternetStackHelper 是一个用于配置和安装多路复用(Multipath)网络堆栈的帮助类。
它提供了一些方法和函数,用于设置和配置多路复用网络堆栈的参数和属性。
Install(nodes) 是 MpInternetStackHelper 类的成员函数,用于将多路复用网络堆栈安装到节点集合 nodes 中。
这样,每个节点都将获得一个配置好的多路复用网络堆栈,以便进行多路复用通信。*/
//    MpInternetStackHelper stack;
//    stack.Install(nodes);

///Pablo
    InternetStackHelper stack;
    stack.SetTcp ("ns3::MpTcpL4Protocol");
    stack.Install (nodes);
/*这段代码使用 InternetStackHelper 对象来配置和安装 TCP/IP 网络堆栈到给定的节点集合中,并将其中的 TCP 协议设置为 MpTcpL4Protocol。
InternetStackHelper 是一个用于配置和安装 TCP/IP 网络堆栈的帮助类。它提供了一些方法和函数,用于设置和配置 TCP/IP 网络堆栈的参数和属性。

SetTcp("ns3::MpTcpL4Protocol") 是 InternetStackHelper 类的成员函数,用于设置 TCP 协议为 MpTcpL4Protocol。
这表示该网络堆栈将使用 Multipath TCP(MPTCP)协议作为其 TCP 协议实现。
Install(nodes) 是 InternetStackHelper 类的成员函数,用于将 TCP/IP 网络堆栈安装到节点集合 nodes 中。
这样,每个节点都将获得一个配置好的 TCP/IP 网络堆栈,以便进行 TCP/IP 通信。
将 TCP 协议设置为 MpTcpL4Protocol 的目的是为了在网络中启用 Multipath TCP 功能,从而实现多路径数据传输。
Multipath TCP 允许同时使用多条路径进行数据传输,以提高带宽利用率、降低延迟和增强网络鲁棒性。*/
/

//这段代码创建了一个 Ipv4InterfaceContainer 类型的向量 ipv4Ints,并使用 PointToPointHelper 创建了一些点对点链路,并为每个链路分配了 IP 地址
    vector<Ipv4InterfaceContainer> ipv4Ints;//这是一个名为 ipv4Ints 的向量,用于存储 Ipv4InterfaceContainer 对象。
/*在这个 for 循环中,使用 PointToPointHelper 创建了一些点对点链路。创建多个点对点链路,并为每个链路分配一个 IP 地址,并将这些接口存储在 ipv4Ints 向量中。
p2plink.SetQueue 设置了链路上的队列类型和参数,p2plink.SetDeviceAttribute 和 p2plink.SetChannelAttribute 设置了链路设备和信道的属性,例如数据速率和延迟。
根据 i 的值不同,设置了不同的数据速率和延迟。*/
    for(int i=0; i < sf; i++)
    {
        // Creation of the point to point link between hots
        PointToPointHelper p2plink;
	p2plink.SetQueue ("ns3::DropTailQueue", "MaxPackets",UintegerValue(queueSize));
	if(i==0)
	{
        	p2plink.SetDeviceAttribute ("DataRate", StringValue("1Mbps"));
            //将数据传输速率属性设置为1Mbps。这意味着在该P2P通道上的数据传输速率将被限制为1Mbps。
            //数据传输速率表示在单位时间内传输的数据量,以Mbps为单位表示。较高的数据传输速率可以提高传输速度和数据吞吐量。
            /*带宽是指在单位时间内传输的数据量,通常以比特每秒(bps)为单位表示。而数据传输速率也是指在单位时间内传输的数据量,通常以比特每秒(bps)或兆比特每秒(Mbps)为单位表示。
            在计算机和通信领域,带宽通常与数据传输速率相关联。数据传输速率描述了设备或通道在单位时间内能够传输的数据量,而带宽则表示设备或通道所支持的最大数据传输速率。
            换句话说,带宽可以视为设备或通道的容量,而数据传输速率则表示实际传输的速度。
            StringValue(“1Mbps”))将P2P通道的数据传输速率属性设置为1Mbps。
            这意味着该P2P通道的数据传输速率将被限制在1Mbps。因此,该通道的带宽也被限制在1Mbps,即该通道在单位时间内最多能够传输1Mbps的数据量。*/
        	p2plink.SetChannelAttribute("Delay", StringValue("100ms"));
            //将延迟属性设置为200ms。
            //延迟是指数据从发送端到接收端所需的时间。较高的延迟可能会导致数据传输的速度变慢,从而影响系统的响应性能。
	}	
	if(i==1)
	{
		p2plink.SetDeviceAttribute ("DataRate", StringValue("1Mbps"));
                p2plink.SetChannelAttribute("Delay", StringValue("200ms"));
	
	}

        NetDeviceContainer netDevices;//创建了一个NetDeviceContainer对象netDevices,用于存储网络设备
        netDevices = p2plink.Install(nodes);
        /*在这里,使用 Ipv4AddressHelper 设置了 IP 地址,并将其分配给点对点链路中的设备。
        通过使用 std::stringstream 构建了一个 IP 地址字符串,并设置了网络地址和子网掩码。然后,使用 Assign 函数将 IP 地址分配给点对点链路上的设备,并将接口存储在 interface 中。
        最后,将 interface 插入到 ipv4Ints 向量中。*/
        // Attribution of the IP addresses
        std::stringstream netAddr;
        netAddr << "10.1." << (i+1) << ".0";
        string str = netAddr.str();

        Ipv4AddressHelper ipv4addr;
        ipv4addr.SetBase(str.c_str(), "255.255.255.0");//使用ipv4addr.SetBase()函数设置了网络地址和子网掩码。这样就确定了每个设备的唯一IP地址
        Ipv4InterfaceContainer interface = ipv4addr.Assign(netDevices);//将IP地址分配给点对点链路上的设备,并将接口存储在Ipv4InterfaceContainer对象interface中。
        ipv4Ints.insert(ipv4Ints.end(), interface);
        //为点对点链路中的设备分配唯一的IP地址,并将接口存储在interface中,同时将接口添加到ipv4Ints向量中。


       // p2plink.EnablePcap ("prueba_11" , nodes, true);
	//这行代码是用来启用 PCAP 跟踪功能,允许将网络数据包记录到文件中。它将网络数据包记录到名为 “prueba_11” 的文件中。
    //nodes 参数指定了要记录的节点集合,true 参数表示要记录传入和传出的数据包。
	/*
	    PointToPointHelper p2plink1;
        p2plink2.SetDeviceAttribute ("DataRate", StringValue("1900kbps"));
        p2plink2.SetChannelAttribute("Delay", StringValue("1ms"));
 
        NetDeviceContainer netDevices2;
        netDevices2 = p2plink2.Install(nodes);
 
         // Attribution of the IP addresses
        std::stringstream netAddr2;
        netAddr2 << "10.1." << 2 << ".0";
        str = netAddr2.str();
 
        Ipv4AddressHelper ipv4addr2;
        ipv4addr2.SetBase(str.c_str(), "255.255.255.0");
        Ipv4InterfaceContainer interface2 = ipv4addr2.Assign(netDevices);
        ipv4Ints.insert(ipv4Ints.end(), interface2);
 
        p2plink2.EnablePcap ("prueba_11" , nodes, true);
这段被注释的代码是创建另一个点对点链路,并为它分配 IP 地址。它类似于之前的代码,只是设置了不同的数据速率、延迟和 IP 地址。
同样,p2plink2.EnablePcap 用于启用 PCAP 跟踪功能。
*/
/*PCAP(Packet Capture)跟踪功能是一种网络数据包捕获和记录的机制。它允许您在网络中捕获传入和传出的数据包,并将其保存到文件中以供后续分析和调试。
PCAP 跟踪功能通常在网络调试、性能分析和安全监控等场景中使用。它可以帮助您诊断网络问题、分析网络性能和检测潜在的安全漏洞。
一旦开启了PCAP跟踪,网络中的所有数据包都会被捕获并写入指定的文件中。您可以在后续的分析中使用网络分析工具(如Wireshark)来查看和解析捕获的数据包。
这可以让您深入了解网络通信,分析协议的行为,检查数据包的内容和结构,并发现任何潜在问题。
在ns-3网络模拟器中,PCAP跟踪功能可以通过EnablePcap()函数来启用。通过指定要记录的节点集合、记录的文件名和是否记录传入/传出的数据包,您可以选择性地启用PCAP跟踪来捕获和记录特定节点的数据包。
总而言之,PCAP跟踪功能可以帮助您捕获和分析网络数据包,提供详细的网络通信信息,以及帮助诊断和解决网络问题。*/
    }

/*
    fstP2Plink.SetDeviceAttribute ("DataRate", StringValue("500Mbps"));
    fstP2Plink.SetChannelAttribute("Delay", StringValue("10ms"));
    NetDeviceContainer fstDevices;
    fstDevices = fstP2Plink.Install(nodes);
    这段被注释的代码是创建第二个点对点链路,并为链路设置数据速率和延迟属性。在这里,数据速率设置为500Mbps,延迟设置为10ms。
    fstDevices 是一个 NetDeviceContainer 对象,用于存储创建的设备。
*/
    // Installation of the IPv4 stack on each host
    //InternetStackHelper stack;
    //stack.Install(nodes);

    //Ipv4GlobalRoutingHelper::PopulateRoutingTables();

    // Creation of the 2nd point to point link between hosts
/*
    sndP2Plink.SetDeviceAttribute ("DataRate", StringValue("2200Mbps"));
    sndP2Plink.SetChannelAttribute("Delay", StringValue("10ms"));
    // Data rate and channel's delay are let in default values
    NetDeviceContainer sndDevices;
    sndDevices = sndP2Plink.Install(nodes);
    这段被注释的代码是创建第三个点对点链路,并为链路设置数据速率和延迟属性。在这里,数据速率设置为2200Mbps,延迟设置为10ms。
    sndDevices 是一个 NetDeviceContainer 对象,用于存储创建的设备。
*/
    // Creation of the 3rd point to point link between hots
/*
    trdP2Plink.SetDeviceAttribute ("DataRate", StringValue("3Mbps"));
    trdP2Plink.SetChannelAttribute("Delay", StringValue("10ms"));
    NetDeviceContainer trdDevices;
    trdDevices = trdP2Plink.Install(nodes);
    这段被注释的代码是创建第三个点对点链路,并为链路设置数据速率和延迟属性。在这里,数据速率设置为3Mbps,延迟设置为10ms。
    trdDevices 是一个 NetDeviceContainer 对象,用于存储创建的设备。
*/
    // Enabling PCAP traces to be loged



    ///Pabloo//
/*这部分被注释的代码涉及 IP 地址的分配。
在这段代码中,首先创建了一个 Ipv4AddressHelper 对象 fstAddrs,然后使用 SetBase 函数设置了基准 IP 地址和子网掩码。
接下来,调用 Assign 函数将 IP 地址分配给 fstDevices,并将结果存储在 fstInt 中。
同样的过程也适用于第二个点对点链路,使用 sndAddrs 设置基准 IP 地址和子网掩码,并将 IP 地址分配给 sndDevices,结果存储在 sndInt 中。
最后,被注释的代码还包含了一个与第三个点对点链路相关的部分,其中使用 trdAddrs 设置基准 IP 地址和子网掩码,并将 IP 地址分配给 trdDevices,结果存储在 trdInt 中。
根据您的需求,您可以取消注释这些代码来分配 IP 地址给相应的设备和接口。
请注意,这些代码只是提供了一个示例分配 IP 地址的方法,实际上您可能需要根据网络拓扑和需求自定义 IP 地址分配。*/

    //PointToPointHelper::EnablePcapAll("mptcp");

//    Ptr<NetDevice> temp = nodes.Get(1)->GetObject <NetDevice> ();
//
//
//    PointToPointHelper::EnablePcap("mptcp", temp, false, true);

///
/*
    // Attribution of the IP addresses
    Ipv4AddressHelper fstAddrs;
    fstAddrs.SetBase("10.1.1.0", "255.255.255.0");
    Ipv4InterfaceContainer fstInt = fstAddrs.Assign(fstDevices);

    Ipv4AddressHelper sndAddrs;
    sndAddrs.SetBase("10.1.2.0", "255.255.255.0");
    Ipv4InterfaceContainer sndInt = sndAddrs.Assign(sndDevices);
*/
/*
    Ipv4AddressHelper trdAddrs;
    trdAddrs.SetBase("10.1.3.0", "255.255.255.0");
    Ipv4InterfaceContainer trdInt = trdAddrs.Assign(trdDevices);
*/
    // Configuration of the Client/Server application

 Pablo Garrido -UC
    uint32_t servPort = 5000;//服务器应用程序的端口号
    NS_LOG_INFO ("address " << ipv4Ints[0].GetAddress (1));


/*在这段被注释的代码中,首先定义了一个 servPort 变量,用于表示服务器应用程序的端口号。
然后,通过 GetAddress() 函数获取了服务器节点的 IP 地址,并通过 NS_LOG_INFO 函数输出到日志中。
接下来,使用 ObjectFactory 创建了一个 ns3::MpTcpPacketSink 对象,并设置了相关属性。
SetTypeId() 函数用于设置对象的类型ID。Set() 函数用于设置对象的属性,包括协议类型、本地地址和算法参数。
最后,通过 Create() 函数创建了一个应用程序对象 sapp,该对象是根据 m_sf 配置的属性创建的。然后,将该应用程序对象附加到服务器节点上,以实现服务器的功能。*/
//    uint32_t servPort = 5000;
//    NS_LOG_INFO ("address " << ipv4Ints[0].GetAddress (1));
//
//    ObjectFactory m_sf;
//    m_sf.SetTypeId("ns3::MpTcpPacketSink");
//    m_sf.Set("Protocol", StringValue ("ns3::TcpSocketFactoryImpl"));
//    m_sf.Set("Local", AddressValue(InetSocketAddress (ipv4Ints[0].GetAddress (1), servPort)));
//    m_sf.Set("algopr", UintegerValue ((uint32_t) pr));
//
//    Ptr<Application> sapp = m_sf.Create<Application> ();
//    server->AddApplication(sapp);
//创建和配置一个 ns3::MpTcpPacketSink 应用程序对象,并将其附加到服务器节点上。
  MpTcpPacketSinkHelper help("ns3::TcpSocketFactory",(InetSocketAddress (ipv4Ints[0].GetAddress (1), servPort)), pr);
  ApplicationContainer sapp=help.Install(server);
  //使用 MpTcpPacketSinkHelper 配置 MPTCP 数据包接收器,并将其安装在服务器节点上。这样,服务器就可以接收并处理从客户端发送的 MPTCP 数据包
//






//创建了一个应用程序容器,并将应用程序添加到容器中,然后启动和停止应用程序。
/*
    Ptr<MpTcpPacketSink> mptcpPktSnk = (Ptr<MpTcpPacketSink>) sapp;
    Ptr<MpTcpSocketImpl> sSocket = mptcpPktSnk->getMpTcpSocket ();
    sSocket->SetPacketReorderAlgo (pr);
*/
    ApplicationContainer Apps;
    Apps.Add(sapp);
//    Apps.Add(capp);
//将MPTCP数据包接收器助手安装到节点0上,并将应用程序容器存储在Apps中。


    //ApplicationContainer serverApps = sink.Install(server);
    Apps.Start(Seconds(0.0));//在0秒开始运行MPTCP发送器应用程序。
    Apps.Stop(Seconds(simDuration));//static const double simDuration    = 100.0;
//在经过simDuration秒后停止ApplicationContainer中的所有应用程序对象。这个操作将触发所有应用程序对象的停止行为,使它们停止发送或接收数据。

//连接到服务器,并设置连接的回调、数据发送的回调、关闭连接的回调等。
    //Ptr<Socket> localSocket = Socket::CreateSocket(client, TcpSocketFactory::GetTypeId());
    lSocket = new MpTcpSocketBase (client);
    /*
    localSocket->SetNode(client);
    Ptr<MpTcpL4Protocol> mptcp = client->GetObject<MpTcpL4Protocol> ();
    localSocket->SetMpTcp(mptcp);
    */
    //lSocket->SetCongestionCtrlAlgo (Linked_Increases);
    //lSocket->SetCongestionCtrlAlgo (RTT_Compensator);
    //lSocket->SetCongestionCtrlAlgo (cc);
    lSocket->SetCongestionCtrlAlgo (Uncoupled_TCPs);
    //lSocket->SetCongestionCtrlAlgo(Fully_Coupled);
    lSocket->SetDataDistribAlgo (Round_Robin);
/*要实现耦合的拥塞控制算法,您需要进行以下步骤:
取消注释日志记录代码:在代码中找到注释掉的日志记录代码段,并将其取消注释。这样可以启用相应组件的日志记录,以便跟踪拥塞控制算法的行为和状态。
设置耦合的拥塞控制算法:在StartFlow函数中,找到以下代码行:
lSocket->SetCongestionCtrlAlgo("Uncoupled_TCPs");
将其修改为:
lSocket->SetCongestionCtrlAlgo("Fully_Coupled");
这样就将拥塞控制算法设置为耦合的方式,各个子流共享一个拥塞控制状态。
确保代码中已包含相关的头文件:根据您使用的拥塞控制算法和其他组件,确保代码中包含了正确的头文件。如果取消注释的日志记录代码提示找不到相关的头文件,请添加相应的头文件。
重新编译和运行代码:在您进行了上述修改后,重新编译和运行代码。在运行过程中,将会生成相应的日志记录,可以通过查看日志来跟踪耦合拥塞控制算法的行为和状态。*/
 /*lSocket->SetCongestionCtrlAlgo (Linked_Increases);:这行代码设置拥塞控制算法为 "Linked_Increases",即使用增量链路拥塞控制算法。如果取消注释这行代码,那么该算法将被应用。
lSocket->SetCongestionCtrlAlgo (RTT_Compensator);:这行代码设置拥塞控制算法为 "RTT_Compensator",即使用往返时间补偿拥塞控制算法。如果取消注释这行代码,那么该算法将被应用。
lSocket->SetCongestionCtrlAlgo (cc);:这行代码设置拥塞控制算法为 "cc",即使用 cc 拥塞控制算法。如果取消注释这行代码,那么该算法将被应用。
lSocket->SetCongestionCtrlAlgo (Uncoupled_TCPs);:这行代码设置拥塞控制算法为 "Uncoupled_TCPs",即使用非耦合的 TCPs 拥塞控制算法。如果取消注释这行代码,那么该算法将被应用。
lSocket->SetCongestionCtrlAlgo(Fully_Coupled);:这行代码设置拥塞控制算法为 "Fully_Coupled",即使用耦合的拥塞控制算法。如果取消注释这行代码,那么该算法将被应用。*/   
    


/*SetPacketReorderAlgo函数用于设置包重新排序算法。
pr是一个算法类型的参数,它指定了包重新排序的算法。
Bind函数用于绑定lSocket对象到一个地址和端口。
SetSegmentSize函数用于设置段大小。1500是一个参数,它指定了段的大小。
SetMpWindowTraceCallback函数用于设置多路径窗口跟踪回调函数。
MakeCallback用于将ProprietaryTracing::DefaultWindowTrace函数作为回调函数,并将pTracing作为回调函数的参数。*/
/*"Eifel"包重新排序算法是一种用于多路径传输控制协议(MPTCP)的包重新排序算法。该算法的目的是减少数据包乱序带来的性能损失,并提高数据传输的效率。
"Eifel"算法的基本原理是,在发送方维护一个发送窗口,并在接收方维护一个接收窗口。发送方根据接收方的窗口大小和期望接收的数据包顺序,决定发送哪些数据包。接收方根据接收到的数据包的顺序,确定是否需要发送确认(ACK)。如果接收方检测到数据包乱序,它可以发送一个SACK(Selective ACK)报文通知发送方重新发送乱序的数据包。
"Eifel"算法的优点是能够有效地减少数据包乱序对传输性能的影响。它可以自适应地调整发送速率,提高网络吞吐量,并降低延迟。此外,它还可以提供对丢包的快速恢复机制,以保证数据传输的可靠性。*/    

    //lSocket->SetPacketReorderAlgo (Eifel);
    lSocket->SetPacketReorderAlgo (pr);//设置了lSocket的数据包重排序算法,其中pr是数据包重排序算法对象
    lSocket->Bind ();//使用Bind()函数将lSocket绑定到本地地址和端口,以便可以接收和发送数据。
    lSocket->SetSegmentSize(1500);//设置了lSocket的分段大小为1500字节。这个设置可以影响数据包的传输和分段行为。
    lSocket->SetMpWindowTraceCallback(MakeCallback (&ProprietaryTracing::DefaultWindowTrace, pTracing));
    //设置了lSocket的多路径窗口追踪回调函数。
    //在这里,通过MakeCallback()函数将ProprietaryTracing::DefaultWindowTrace函数绑定到pTracing对象上,以便在多路径传输过程中追踪和记录窗口变化的信息。
    // Trace changes to the congestion window
    //Config::ConnectWithoutContext ("/NodeList/0/$ns3::MpTcpSocketBase/subflows/0/CongestionWindow", MakeCallback (&CwndTracer));

    //Config::SetDefault("ns3::MpTcpSocketBase::LargePlotting", BooleanValue(true));
    // ...and schedule the sending "Application"; This is similar to what an
    // ns3::Application subclass would do internally.
    //MpTcpSubFlow::StartTracing("prueba_11_1");

    /*
    // 追踪拥塞窗口的变化
     // Config::ConnectWithoutContext ("/NodeList/0/$ns3::MpTcpSocketBase/subflows/0/CongestionWindow", MakeCallback (&CwndTracer));
    // Config::SetDefault("ns3::MpTcpSocketBase::LargePlotting", BooleanValue(true)); 
    // …然后调度发送 "Application";这类似于一个 ns3::Application 子类在内部执行的操作。 // MpTcpSubFlow::StartTracing(“prueba_11_1”);
    上述代码的注释内容解释了一些操作。
    第一行代码使用Config::ConnectWithoutContext()函数来连接到拥塞窗口的变化,以便追踪窗口的变化情况。具体实现是通过提供一个回调函数(&CwndTracer)来处理这些变化。
    第二行代码使用Config::SetDefault()函数来设置MpTcpSocketBase::LargePlotting参数为true。这个设置可以启用一个大型绘图功能,用于更详细地绘制拥塞窗口和其他相关信息。
    最后一行代码调用MpTcpSubFlow::StartTracing()函数,传入一个字符串参数"prueba_11_1"来开始追踪操作。这里的"prueba_11_1"可能是用于标识和保存追踪数据的文件名或标识符。
    这些代码片段的目的是在网络仿真中对拥塞窗口的变化进行追踪和记录,以便后续分析和评估。*/

    Simulator::ScheduleNow (&StartFlow, lSocket, ipv4Ints[0].GetAddress (1), servPort);
/*这行代码使用Simulator::ScheduleNow()函数在当前仿真时间立即调度一个函数StartFlow的执行。
StartFlow函数的参数包括lSocket(一个Ptr<Socket>对象)、ipv4Ints[0].GetAddress(1)(一个IP地址对象)和servPort(一个端口号)。
通过调用Simulator::ScheduleNow()函数并传入StartFlow函数及其参数,可以立即(在当前仿真时间)执行StartFlow函数。*/
//StartFlow函数用于启动流程。
//首先设置最大子流数量、最小子流数量、源地址和缓冲区大小等参数。
//然后调用Connect函数连接到指定的服务器地址和端口。如果连接成功,设置连接成功回调函数、数据发送回调函数和关闭回调函数等。
//最后,启动拥塞窗口跟踪,并调用WriteUntilBufferFull函数发送数据。

    // Finally, set up the simulator to run.  The 1000 second hard limit is a
    // failsafe in case some change above causes the simulation to never end
    //最后,设置仿真器开始运行。设置1000秒的硬限制是为了防止以上更改导致仿真永远无法结束。
    //安装 IPv4 路由表,停止、运行和销毁模拟器。
    Simulator::Stop (Seconds(simDuration + 10.0));//在经过simDuration + 10.0秒后停止NS-3仿真器的运行。这个操作将停止整个仿真流程,包括停止所有的应用程序、网络设备和节点。
    Simulator::Run ();
    Simulator::Destroy();

NS_LOG_LOGIC("mpTopology:: simulation ended");
    return 0;
}









//定义了一些辅助函数,如连接成功、连接失败、写入数据直到缓冲区满等函数。
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//begin implementation of sending "Application"
//StartFlow函数用于启动流程。首先设置最大子流数量、最小子流数量、源地址和缓冲区大小等参数。
//然后调用Connect函数连接到指定的服务器地址和端口。
//如果连接成功,设置连接成功回调函数、数据发送回调函数和关闭回调函数等。最后,启动拥塞窗口跟踪,并调用WriteUntilBufferFull函数发送数据。
void StartFlow(Ptr<MpTcpSocketBase> localSocket, Ipv4Address servAddress, uint16_t servPort)
{
  NS_LOG_LOGIC("Starting flow at time " <<  Simulator::Now ().GetSeconds ());
  //localSocket->Connect (InetSocketAddress (servAddress, servPort));//connect
  lSocket->SetMaxSubFlowNumber(5);
  lSocket->SetMinSubFlowNumber(3);
  lSocket->SetSourceAddress(Ipv4Address("10.1.1.1"));
  lSocket->allocateSendingBuffer(sendBufSize);
  lSocket->allocateRecvingBuffer(recvBufSize);
  // the following buffer is uesed by the received to hold out of sequence data
  lSocket->SetunOrdBufMaxSize(50);


  int connectionState = lSocket->Connect( servAddress, servPort);
//NS_LOG_LOGIC("mpTopology:: connection request sent");
  // tell the tcp implementation to call WriteUntilBufferFull again
  // if we blocked and new tx buffer space becomes available

  if(connectionState == 0)
  {
      lSocket->SetConnectCallback  (MakeCallback (&connectionSucceeded), MakeCallback (&connectionFailed));
      lSocket->SetDataSentCallback (MakeCallback (&WriteUntilBufferFull));
      lSocket->SetCloseCallbacks   (MakeCallback (&HandlePeerClose), MakeCallback(&HandlePeerError));
      lSocket->GetSubflow(0)->StartTracing ("CongestionWindow");
  }else
  {
      //localSocket->NotifyConnectionFailed();
      NS_LOG_LOGIC("mpTopology:: connection failed");
  }
  //WriteUntilBufferFull (localSocket);
}

/*这段代码是关于建立连接和设置回调函数的逻辑。
首先,使用lSocket->Connect(servAddress, servPort)函数尝试建立与服务器地址和端口的连接。返回的connectionState表示连接状态,其中0表示连接成功,其他值表示连接失败。
如果连接成功(connectionState == 0),则进行以下操作:
使用lSocket->SetConnectCallback()函数设置连接成功的回调函数为connectionSucceeded,设置连接失败的回调函数为connectionFailed。
使用lSocket->SetDataSentCallback()函数设置数据发送的回调函数为WriteUntilBufferFull,即在发送缓冲区有空间时再次调用该函数进行数据发送。
使用lSocket->SetCloseCallbacks()函数设置连接关闭的回调函数为HandlePeerClose,设置连接错误的回调函数为HandlePeerError。
使用lSocket->GetSubflow(0)->StartTracing()函数开始追踪拥塞窗口的变化,将其命名为"CongestionWindow"。
如果连接失败,将输出一条日志信息表示连接失败。
通过以上操作,可以设置连接的回调函数和追踪拥塞窗口的变化,以便进行连接管理和性能分析。*/


//connectionSucceeded函数是连接成功的回调函数。在函数中打印连接成功的信息,并使用Simulator::Schedule函数安排定时调用WriteUntilBufferFull函数和CloseConnection函数。
void connectionSucceeded (Ptr<Socket> localSocket)
{
    NS_LOG_FUNCTION_NOARGS();
    NS_LOG_INFO("mpTopology: Connection requeste succeed");
    Simulator::Schedule (Seconds (1.0), &WriteUntilBufferFull, lSocket, 0);
    Simulator::Schedule (Seconds (simDuration), &CloseConnection, lSocket);
    //Ptr<MpTcpSocketImpl> lSock = localSocket;
    // advertise local addresses
    //lSocket->InitiateSubflows();
    //WriteUntilBufferFull(lSocket, 0);
}
//connectionFailed函数是连接失败的回调函数。在函数中打印连接失败的信息,并调用Close函数关闭连接。
void connectionFailed (Ptr<Socket> localSocket)
{
    NS_LOG_FUNCTION_NOARGS();
    NS_LOG_INFO("mpTopology: Connection requeste failure");
    lSocket->Close();
}
//处理对等方关闭连接的情况。在函数中打印连接关闭的信息,并调用Close函数关闭连接。
void HandlePeerClose (Ptr<Socket> localSocket)
{
    NS_LOG_FUNCTION_NOARGS();
    NS_LOG_INFO("mpTopology: Connection closed by peer");
    lSocket->Close();
}
//处理对等方连接错误的情况。在函数中打印连接错误的信息,并调用Close函数关闭连接。
void HandlePeerError (Ptr<Socket> localSocket)
{
    NS_LOG_FUNCTION_NOARGS();
    NS_LOG_INFO("mpTopology: Connection closed by peer error");
    lSocket->Close();
}
//关闭连接。在函数中调用Close函数关闭连接,并打印当前传输字节数和总传输字节数的信息。
void CloseConnection (Ptr<Socket> localSocket)
{
    lSocket->Close();
    NS_LOG_LOGIC("mpTopology:: currentTxBytes = " << currentTxBytes);
    NS_LOG_LOGIC("mpTopology:: totalTxBytes   = " << totalTxBytes);
    NS_LOG_LOGIC("mpTopology:: connection to remote host has been closed");
}

/*
void variateDelay(PointToPointHelper P2Plink)
{
    //NS_LOG_INFO ("variateDelay -> old delay == " << P2Plink.GetDelay());
    NS_LOG_INFO ("variateDelay");
    std::stringstream strDelay;
    int intDelay = rand() % 100;
    strDelay << intDelay << "ms";
    P2Plink.SetChannelAttribute("Delay", StringValue(strDelay.str()));

    NS_LOG_INFO ("New delay == " << strDelay.str());
}
*/


//用于随机变化点对点链路的延迟
/*函数的输入参数是一个Ptr<Node>类型的指针,表示要进行延迟变化的节点。
函数的主要逻辑如下:
首先,通过调用node->GetObject<Ipv4L3Protocol>()函数获取节点上的Ipv4L3Protocol对象,并将其赋值给ipv4。
然后,使用一个循环遍历节点上的每个接口。
在循环中,获取接口的地址和相关的设备信息,并检查是否为回环地址(回环地址是不需要考虑的)。
如果不是回环地址,获取接口的网络设备和通道对象。
使用P2Plink->GetAttribute(string("Delay"), delay)获取当前连接的延迟,将其保存在delay变量中。
将当前延迟转化为秒,并保存在oldDelay变量中。
生成一个0到100之间的随机数,并将其乘以0.001,得到一个新的延迟值。
计算新延迟与旧延迟之间的误差,并采用简单的线性插值计算出一个新的延迟值。
使用P2Plink->SetAttribute(string("Delay"), StringValue(strDelay.str()))将新的延迟值设置到通道的延迟属性上。
使用P2Plink->GetAttribute(string("Delay"), delay)获取新的延迟值,并将其保存在delay变量中。
通过这个函数,可以模拟网络中连接的延迟的随机变化,以测试和评估网络的性能和鲁棒性。*/
void variateDelay (Ptr<Node> node)
{
    //NS_LOG_INFO ("variateDelay");

    Ptr<Ipv4L3Protocol> ipv4 = node->GetObject<Ipv4L3Protocol> ();
    TimeValue delay;
    for(uint32_t i = 0; i < ipv4->GetNInterfaces(); i++)
    {
        //Ptr<NetDevice> device = m_node->GetDevice(i);
        Ptr<Ipv4Interface> interface = ipv4->GetInterface(i);
        Ipv4InterfaceAddress interfaceAddr = interface->GetAddress (0);
        // do not consider loopback addresses
        if(interfaceAddr.GetLocal() == Ipv4Address::GetLoopback())
        {
            // loopback interface has identifier equal to zero
            continue;
        }

        Ptr<NetDevice> netDev =  interface->GetDevice();
        Ptr<Channel> P2Plink  =  netDev->GetChannel();
        P2Plink->GetAttribute(string("Delay"), delay);
        double oldDelay = delay.Get().GetSeconds();
        //NS_LOG_INFO ("variateDelay -> old delay == " << oldDelay);
        std::stringstream strDelay;
        double newDelay = (rand() % 100) * 0.001;
        double err = newDelay - oldDelay;
        strDelay << (0.95 * oldDelay + 0.05 * err) << "s";
        P2Plink->SetAttribute(string("Delay"), StringValue(strDelay.str()));
        P2Plink->GetAttribute(string("Delay"), delay);
        //NS_LOG_INFO ("variateDelay -> new delay == " << delay.Get().GetSeconds());
    }
}


//WriteUntilBufferFull函数用于发送数据直到发送缓冲区满或达到总发送字节数。
//在一个循环中,检查当前已发送的字节数是否小于总发送字节数,并且发送缓冲区是否有可用空间。
//如果满足条件,计算剩余字节数、要写入的字节数和当前写入位置。调用FillBuffer函数将数据填充到发送缓冲区,并更新已发送的字节数。然后调用SendBufferedData函数发送缓冲区中的数据。
void WriteUntilBufferFull (Ptr<Socket> localSocket, unsigned int txSpace)
{
    NS_LOG_FUNCTION_NOARGS();

    //uint32_t txSpace = localSocket->GetTxAvailable ();
  while (currentTxBytes < totalTxBytes && lSocket->GetTxAvailable () > 0)
  {
      uint32_t left    = totalTxBytes - currentTxBytes;
      uint32_t toWrite = std::min(writeSize, lSocket->GetTxAvailable ());
      toWrite = std::min( toWrite , left );
      uint32_t dataOffset = currentTxBytes % writeSize;
//NS_LOG_LOGIC("mpTopology:: data already sent ("<< currentTxBytes <<") data buffered ("<< toWrite << ") to be sent subsequentlly");
      int amountBuffered = lSocket->FillBuffer (&data[dataOffset], toWrite);
      currentTxBytes += amountBuffered;

     // variateDelay(client);
/*
      variateDelay(sndP2Plink);

      variateDelay(trdP2Plink);
*/

      lSocket->SendBufferedData();
  }

/*
  if ( schedule == true )
  {
      // we will be called again when new tx space becomes available.
      NS_LOG_FUNCTION ("we have to wait a while before trying to send new data");
      //Simulator::Schedule (Seconds (2.0), &MpTcpSocketImpl::SendBufferedData, lSocket);
      Timer timer = Timer ( Timer::CANCEL_ON_DESTROY );
      timer.SetFunction ( &WriteUntilBufferFull );
      timer.Schedule ( Seconds (2.01) );
  }
*/

  //lSocket->SendBufferedData ();
  //NS_LOG_LOGIC("mpTopology::WriteUntilBufferFull leaving !");

}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值