Fifth.cc 예제 파일 설멸

Fifth example scenario(2)

다섯번째 시나리오의 경우 소스코드도 길고 내용도 많아서 2개의 포스팅으로 나눠 다루겠다고 했는데요, 드디어 2번째 포스팅을 해보도록 하겠습니다. 지난 포스팅에서는 어떻게 사용자가 어플리케이션을 만들수 있는지 살펴보고 다섯번째 시나리오에서 사용할 어플리케이션을 소개하였습니다. 이번 포스팅에서는 앞서 소개한 어플리케이션을 사용하는 네트워크 시나리오를 소개하도록 하겠습니다. 먼저 네트워크 토폴로지를 소개하도록 하겠습니다.

스크린샷 2018-12-28 오후 10.52.54

위의 네트워크 토폴로지를 보시면 아마 first.cc 시나리오의 네트워크 토폴로지와 다를게 없다고 생각하실수 있습니다. 실제로 네트워크 통신채널은 point-to-point를 사용하며 네트워크에 2개의 노드 밖에 존재하지 않기 때문에 first.cc와 아예 똑같은 네트워크 토폴로지를 갖습니다. 그러나 first.cc와 다른 부분은 TCP/IP layer 중 transmission layer가 UDP에서 TCP로 변경되었습니다. 또한 first.cc 시나리오에서는 point-to-point 채널이 에러가 발생하지 않았지만 이번 시나리오에서는 0.001%의 ErrorRate를 갖고 있습니다. 또 새로운 SinkApplication을 사용합니다. 이 어플리케이션은 클라이언트로부터 받은 패킷을 버리기만 하는 어플리케이션입니다. 서버에서 SinkApplication을 사용하기 때문에 이번 시나리오에서는 서버에서 클라이언트로 가는 패킷을 ACK 이외에는 아무것도 없습니다. 그럼 소스코드를 살펴보도록 하겠습니다.

Source Code

/*
이전 소스코드와 지금 소스코드가 합쳐져 1개의 시나리오 파일을 만듭니다.  
길이 문제로 이전 소스코드는 포함하지 않았습니다.
*/

// Tracing에 사용할 CallBack 함수 (혹은 Trace Sink라고도 부름)로 현재 Cwnd의 값을 출력한다.
static void
CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
{
  NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "\t" << newCwnd);
}

// Tracing에 사용할 CallBack 함수 (혹은 Trace Sink라고도 부름)로 언제 Physical layer에서 packet loss가 발생하는지 출력한다.
static void
RxDrop (Ptr<const Packet> p)
{
  NS_LOG_UNCOND ("RxDrop at " << Simulator::Now ().GetSeconds ());
}

int
main (int argc, char *argv[])
{

  // CommandLine 객체를 이용하면 커맨드라인을 통해 파라미터를 받고 사용할 수 있다.
  CommandLine cmd;
  cmd.Parse (argc, argv);

  // 네트워크 토폴로지에 포함되는 2개의 노드를 만든다.
  NodeContainer nodes;
  nodes.Create (2);

  /*
  2개의 노드를 연결해줄 point-to-point 채널을 만든다.
  point-to-point 채널은 5Mbps의 DataRate를 가지고, 2ms의 Delay를 갖는다.
  */
  PointToPointHelper pointToPoint;
  pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
  pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));

  /*
  노드 2개를 point-to-point로 연결한다.
  point-to-point로 노드를 연결하게 되면 NIC에 해당하는 device 객체를 얻을 수 있다.
  */
  NetDeviceContainer devices;
  devices = pointToPoint.Install (nodes);

  /*
  point-to-point 채널에 ErrorRate를 주기 위해 객체를 선언한다.
  ErrorRate를 0.001%로 설정하고 서버쪽에 ErrorRate를 설정해준다.
  */
  Ptr<RateErrorModel> em = CreateObject<RateErrorModel> ();
  em->SetAttribute ("ErrorRate", DoubleValue (0.00001));
  devices.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em));

  // TCP/IP 스택을 2개의 노드에 설치해준다.
  InternetStackHelper stack;
  stack.Install (nodes);

  // 2개의 노드에 서브넷 아이디가 "10.1.1.0", 서브넷 마스크가 "255.255.255.0"인 ip를 할당해준다.
  Ipv4AddressHelper address;
  address.SetBase ("10.1.1.0", "255.255.255.252");
  Ipv4InterfaceContainer interfaces = address.Assign (devices);

  /*
  서버에서 사용할 SinkApplication을 만들어준다.
  SinkApplication의 포트와 ip를 설정해준다.
  어플리케이션 소켓은 TCP 소켓을 사용할 것이라고 넘겨준다.
  SinkApplication은 0초에 실행해서 20초에 종료한다.
  */
  uint16_t sinkPort = 8080;
  Address sinkAddress (InetSocketAddress (interfaces.GetAddress (1), sinkPort));
  PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
  ApplicationContainer sinkApps = packetSinkHelper.Install (nodes.Get (1));
  sinkApps.Start (Seconds (0.));
  sinkApps.Stop (Seconds (20.));

  /*
  이 시나리오에서 사용자가 정의한 어플리케이션이 사용할 TCP 소켓을 만든다.
  만든 TCP 소켓 객체에 Tracing을 추가하여 CWND 변화를 출력한다.
  */
  Ptr<Socket> ns3TcpSocket = Socket::CreateSocket (nodes.Get (0), TcpSocketFactory::GetTypeId ());
  ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndChange));

  /*
  앞서 정의한 어플리케이션의 객체를 만들고, 어플리케이션의 property를 설정해준다.
  어플리케이션을 첫번째 노드에 설치하고 1초에 어플리케이션을 시작하고 20초에 어플리케이션을 종료한다.
  */
  Ptr<MyApp> app = CreateObject<MyApp> ();
  app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("1Mbps"));
  nodes.Get (0)->AddApplication (app);
  app->SetStartTime (Seconds (1.));
  app->SetStopTime (Seconds (20.));

  /*
  point-to-point 채널을 이용하여 두 노드를 연결하면 얻을 수 있는 Device 객체에 Tracing을 추가하여 packet loss를 출력한다.
  */
  devices.Get (1)->TraceConnectWithoutContext ("PhyRxDrop", MakeCallback (&RxDrop));

  Simulator::Stop (Seconds (20));
  Simulator::Run ();
  Simulator::Destroy ();

  return 0;
}

실행결과

1.00419	536
1.0093	1072
1.01528	1608
1.02167	2144
1.02999	2680
1.03831	3216
1.04663	3752
1.05495	4288
1.06327	4824
1.07159	5360
1.07991	5896
1.08823	6432
1.09655	6968
1.10487	7504
1.11319	8040
1.12151	8576
1.12983	9112
RxDrop at 1.13696
1.13815	9648
1.1548	1072
1.16476	1340
1.17232	1554
1.18064	1738
1.18896	1903
1.19728	2053
1.2056	2192
1.21392	2323
1.22224	2446
1.23056	2563
1.23888	2675
1.2472	2782
1.25552	2885
1.26384	2984
1.27216	3080
1.28048	3173
1.2888	3263
1.29712	3351
1.30544	3436
1.31376	3519
1.32208	3600
1.3304	3679
1.33872	3757
1.34704	3833
1.35536	3907
1.36368	3980
1.372	4052
1.38032	4122
1.38864	4191
1.39696	4259
RxDrop at 1.4032
1.41272	4326
1.42104	1072
1.431	1340
RxDrop at 1.43648

결과가 너무 길어 1.5초까지의 결과만 가져와 봤습니다. 1.3304 3679의 형태로 출력되는 것은 CWND에 대한 Tracing이고 RxDrop at 1.4032의 형태로 출력되는 것은 Physical layer에 대한 Tracing입니다. RxDrop이 발생하는 이유는 소스코드에서 Error Rate를 0.001%로 설정해 줬기 때문입니다. 위의 Tracing 결과를 그래프로 그려보도록 하겠습니다.

fifth-cc-result

파란색 실선은 CWND의 크기를 Byte 단위로 나타낸 것이며 붉은색 점선은 packet loss를 나타낸 것입니다. CWND의 크기가 계속해서 증가하다 packet loss가 발생하면 packet 1개의 크기로 줄어든다는 것을 확인할 수 있습니다. 기본적으로 설정되어 있는 TCP congestion control 알고리즘은 New Reno입니다. 일반적으로 New Reno에서 보이는 CWND 그래프는 아래와 같습니다.

스크린샷 2018-12-29 오전 12.10.13

출처

이번 fifth.cc 시나리오를 통해 얻은 CWND 그래프와 실제 CWND 그래프의 형태가 매우 유사하다는 것을 확인할 수 있습니다. fifth.cc 시나리오를 통해 알 수 있었던 것은 Tracing을 이용하면 다양한 시뮬레이션 결과를 얻을 수 있다는 점, 시뮬레이션의 결과를 필요한 형태로 표현하기 용이하다는 점을 알 수 있었습니다. 또한 사용자가 직접 어플리케이션을 정의함으로써 ns-3에 포함되어 있지 않은 어플리케이션을 이용해서 시뮬레이션을 해볼 수 있다는 것 또한 알 수 있었습니다. 다음 예제 시나리오는 fifth.cc와 같은 환경에서 Tracing의 결과를 출력하는 것이 아니라 다른 형태로 나타내는 방법에 대해 소개해보도록 하겠습니다.

카테고리:

업데이트:

댓글남기기