프로그램 공부/네트워크프로젝트

네트워크 프로젝트 4주차

WINDALIKE윈덜릭 2025. 4. 21. 17:12
반응형
SMALL

CommandLine Arguments

시뮬 돌릴 대 '옵션만 바꿔서" 재컴팡리 안하게 해주는 장치

코드에 변수 뚫어놓고 -> 실행할 때 --size=128 이런 식으로 값만 밀어버린다.

 

“CommandLine은 ‘짓고 난 뒤에 다이얼 돌리는 손잡이’.
코드에 AddValue 몇 줄 박아두면,
./waf --run "시나리오 --딜레이=1s --howmany=999" 이렇게 옵션 뿌려 넣어 실험치만 무한 갈아끼울 수 있음 ㅋㅋ 귀찮은 재컴파일은 이제 그만.”

 

구조 한번 맛봐보자

int main(int argc, char* argv[])
{
  /* 0. 디폴트 값 준비 */
  uint32_t  maxPackets = 1;
  std::string delay    = "2ms";
  uint32_t  pktSize    = 1024;
  double    interval   = 1.0;
  std::string bw       = "5Mbps";

  /* 1. 파서 선언 + 훅(hook) 연결 */
  CommandLine cmd;
  cmd.AddValue("howmany",  "Number of packets to echo", maxPackets);
  cmd.AddValue("delay",    "Line Delay",                delay);
  cmd.AddValue("size",     "Packet Size",               pktSize);
  cmd.AddValue("interval", "Interval",                  interval);
  cmd.AddValue("bw",       "BandWidth",                 bw);

  /* 2. 실제 argv 파싱 → 위 변수들에 덮어쓰기 */
  cmd.Parse(argc, argv);

  /* 3. 이후 코드는 수정된 변수 사용 */
  pointToPoint.SetChannelAttribute("Delay",  StringValue(delay));
  pointToPoint.SetDeviceAttribute ("DataRate",StringValue(bw));
  echoClient.SetAttribute("MaxPackets", UintegerValue(maxPackets));
  echoClient.SetAttribute("Interval",   TimeValue(Seconds(interval)));
  echoClient.SetAttribute("PacketSize", UintegerValue(pktSize));

  Simulator::Run();  Simulator::Destroy();
}

 실행‑예

명령효과
./waf --run "scratch/myfirst" 디폴트(1 pkt·2 ms)
./waf --run "scratch/myfirst --howmany=2 --delay=10ms" 2개 전송, 링크 지연 10 ms로 변경
./waf --run "scratch/myfirst --interval=2 --size=128 --bw=1Mbps" 2 초 간격·128B 패킷·1 Mbps 링크로 실험

로그 보면 딱 송수신 시각·횟수가 바뀌는 걸 확인할 수 있다.

 

팁과 주의

포인트설명
변수 타입 추적 uint32_t, double, std::string 전부 자동 파싱 지원.
설명란(Help) cmd.AddValue("delay", "Line Delay", delay); 의 두 번째 인자는 --help 찍을 때 표시.
위치 cmd.Parse() 전에 링크 지연·앱 속성 세팅 같은 코드 넣으면 안 됨—변수 값이 아직 안 바뀐 상태라서.
대량 파라미터 과제·논문용 스위프 실험은 bash for‑loop로 옵션만 바꿔 수백 번 실행하면 끝

 

High-Level Tracing

“로그는 ‘지금 뭐 하고 있냐’ 실시간 중계고
트레이스(PCAP)는 ‘패킷 하나하나 직캠’ 찍어서 파일로 저장해 두는 거다.
한마디로 ‘흔적 남기기’. 나중에 성능 까거나 버그 잡을 때 100% 필요.”

 

트레이싱 시스템 – 큰 그림

깔깔깔 이미지가 크니까 큰그림이지 인정?

Trace Source 일 터지면 바로 실시간 알림 쏘는 센서” 이벤트 발생 지점 (예: NetDevice가 패킷 전송 끝났을 때 PhyTxEnd)
Trace Sink “센서 알림 받아서 로그·그래프 그리는 관제실 콜백 함수·파일 라이터 등
Helper “센서랑 관제실 선 연결 자동 배선공 PcapHelper / AsciiTraceHelper

Source는 모듈 안에 이미 박혀 있음 (불변).
Sink만 유저가 골라서 ‘꽂는’ 구조. 위 이미지에서 ‘Unchanging’ vs ‘Configurable by user’ 박스가 그 얘기.​

 

하이레벨 트레이싱 (귀차니즘 버전)

EnablePcapAll 한 줄 치면 끝

pointToPoint.EnablePcapAll("firstcap");
  • 이름(prefix) 만 넣으면 firstcap-0-0.pcap, firstcap-1-0.pcap … 자동생성
  • 어느 NetDevice가 어느 방향으로 보낸 건지 IPX번호로 구분
    (0‑0 = 노드0 디바이스0)

“와프(waf) 빌드하고 시뮬만 돌려도, 패킷 ‘직캠’이 ns‑3.29/ 폴더에 떡! 하고 떨어짐.”​

# 패킷 찍고
./waf --run "scratch/myfirst --interval=2 --size=128 --howmany=2 --delay=1000ms"

# 바로 해석
tcpdump -nn -tt -r firstcap-0-0.pcap

출력 예

2.000000 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 128
4.000000 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 128
...
  • -nn : DNS·포트 이름 해석 끄고 숫자로 뿌려라
  • -tt : 타임스탬프 그냥 초(sec) 단위 정수로 줘라
  • -r : pcap 읽기 모드

Wireshark? 걍 GUI 버전 tcpdump라 보면 됨. 필터 udp && frame.len==128 딱 치면 원하는 프레임만 추려짐.​

 

Application in ns-3

우리가 그동안 얘를 뭐라고 다뤘냐

현실로 치면 유튜브 켠 크롬 브라우저, 사용자 프로그램(웹 브라우저, ip 등이다), 트래픽을 만드는 주체이고 패킷 만들고(Send) 받는(Recv) 로직 담당. Echo Client, OnOffApp 등 이미 만들어진 놈도 있고, 직접 만들수도 있다 

 

뭐 이렇게 설명을 해왔는데, 좀 더 자세히 들여다보자고 ㅇㅇ

 

자, 얘는 뭐다? Node 위에서 패킷을 뿜어내고 받아먹는 프로그램이야.

 

OnOffApplication OnOffHelper CBR(constant bit rate) 트래픽을 On/Off 패턴으로 뿌림 DataRate, PacketSize, OnTime, OffTime
PacketSink PacketSinkHelper 패킷 받고 끝. 로깅용 Protocol, Local
UdpEcho UdpEchoClient/ServerHelper 클라가 보내면 서버가 그대로 에코 클라 MaxPackets‧Interval‧PacketSize, 서버 Port
UdpClient/Server UdpClient/ServerHelper 순수 UDP 송수신 클라 Interval‧RemoteAddress‧RemotePort,    서버 PacketWindowSize

 

onoffapplication 들여다보자

// 목적지
uint16_t port = 9;
Ipv4Address dst = Ipv4Address("10.1.1.2");

// 헬퍼 생성
OnOffHelper onoff("ns3::UdpSocketFactory",
                  Address(InetSocketAddress(dst, port)));

// 속성 세팅
onoff.SetAttribute("DataRate",   DataRateValue("5Mbps"));
onoff.SetAttribute("PacketSize", UintegerValue(1024));
onoff.SetAttribute("OnTime",
    StringValue("ns3::ConstantRandomVariable[Constant=1.0]"));
onoff.SetAttribute("OffTime",
    StringValue("ns3::ConstantRandomVariable[Constant=1.0]"));

// 노드0에 설치하고 1~10초 가동
ApplicationContainer apps = onoff.Install(nodes.Get(0));
apps.Start(Seconds(1.0));
apps.Stop (Seconds(10.0));

 

  • OnTime/OffTime 둘 다 1 초 ⇒ 1초 뿜고 1초 쉼
  • DataRate × PacketSize = 실측 전송률.

PacketSink

PacketSinkHelper sink("ns3::UdpSocketFactory",
   Address(InetSocketAddress(Ipv4Address::GetAny(), port)));

ApplicationContainer snk = sink.Install(nodes.Get(1));
snk.Start(Seconds(1.0));
snk.Stop (Seconds(10.0));

 

 

결과는 PacketSink가 stdout으로 “Received N bytes” 찍어줌. 분석 끝.

 

UdpEcho 

// 서버(node1)
UdpEchoServerHelper echoSrv(port);
echoSrv.Install(nodes.Get(1)).Start(Seconds(1));

// 클라이언트(node0)
UdpEchoClientHelper echoCli(dst, port);
echoCli.SetAttribute("MaxPackets", UintegerValue(5));
echoCli.SetAttribute("Interval",   TimeValue(Seconds(1)));
echoCli.SetAttribute("PacketSize", UintegerValue(512));
echoCli.Install(nodes.Get(0)).Start(Seconds(2));
  • 보내면 바로 에코. RTT 체크용으로 꿀.

UdpClient/Server

// 서버(node1)
UdpServerHelper udpSrv(port);
udpSrv.Install(nodes.Get(1));

// 클라이언트(node0)
UdpClientHelper udpCli(dst, port);
udpCli.SetAttribute("Interval", TimeValue(MicroSeconds(8000))); // 1 Mbps 맞추려면 계산
udpCli.SetAttribute("MaxPackets", UintegerValue(0));            // 0 = 무한
udpCli.SetAttribute("PacketSize", UintegerValue(1024));
udpCli.Install(nodes.Get(0));
  • Echo 없음. 서버는 받고 카운트만.

생명주기 API – 켜고 끄는 타이밍


apps.Start(t) / apps.Stop(t) 컨테이너 몽땅 스케줄
SetStartTime(t) / SetStopTime(t) 개별 객체 수동 세팅
StartApplication() / StopApplication() 프레임워크가 자동 호출
→ 여기서 소켓 열고 닫음

아무튼 정리하자면,,,

 

  • NodeContainer nodes.Create(…)
  • PointToPoint/Csma 등으로 NetDevice + Channel 설치
  • InternetStackHelper → Ipv4AddressHelper
  • Application Helper 설치 + Start/Stop

 

예시를 들어보자

 

 

노드 2개P2P 5 Mbps / 2 ms 링크
UdpEcho 데모(핑퐁)
OnOffApplication 데모(CBR 뿜뿜)

슬라이드 그림에 나오는 10.1.1.0/24 세그먼트가 전부다.
코드 두 개(week4_ex2_udp_echo.cc, week4_ex2_onoff_app.cc)를 순서대로 보자.


A. week4_ex2_udp_echo.cc – 핑퐁 맛보기

1단계 ‑ 로깅 옵션 먹이기

bool verbose = true;                 // 기본값 ON
CommandLine cmd;
cmd.AddValue("verbose", "log?", verbose);
cmd.Parse(argc, argv);
if (verbose) {
  LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
  LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
}
  • ./waf --run "… --verbose=0" 하면 로그 잠궈버릴 수도 있다.

2단계 ‑ 노드 2개 뚝딱

NodeContainer p2pNodes;
p2pNodes.Create(2);

3단계 ‑ 링크&NIC 장착

PointToPointHelper p2p;
p2p.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
p2p.SetChannelAttribute("Delay",    StringValue ("2ms"));

NetDeviceContainer p2pDevs = p2p.Install(p2pNodes);
  • DeviceAttribute = NIC 속도, ChannelAttribute = “가상 UTP” 지연.

4단계 ‑ IP 스택 + 주소

InternetStackHelper stack;
stack.Install(p2pNodes);

Ipv4AddressHelper addr;
addr.SetBase("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer ifs = addr.Assign(p2pDevs);
  • ifs.GetAddress(0) → 10.1.1.1, ifs.GetAddress(1) → 10.1.1.2.

5단계 ‑ Echo 서버(node1) 세팅

UdpEchoServerHelper echoServer(9);                 // 포트 9 (discard)
ApplicationContainer sApps = echoServer.Install(p2pNodes.Get(1));
sApps.Start(Seconds(1));
sApps.Stop (Seconds(10));

6단계 ‑ Echo 클라이언트(node0)

UdpEchoClientHelper echoClient(ifs.GetAddress(1), 9);
echoClient.SetAttribute("MaxPackets", UintegerValue(100));
echoClient.SetAttribute("Interval",   TimeValue(Seconds(1)));
echoClient.SetAttribute("PacketSize", UintegerValue(1024));

ApplicationContainer cApps = echoClient.Install(p2pNodes.Get(0));
cApps.Start(Seconds(2));
cApps.Stop (Seconds(10));
  • 2초부터 10초까지 1초 간격으로 100개까지만 쏨.

7단계 ‑ 패킷 캡처

p2p.EnablePcapAll("second");     // second-0-0.pcap / second-1-0.pcap

8단계 ‑ 시뮬레이터 스타트

Simulator::Run();
Simulator::Destroy();

 

뇌리에 박기 – UDP 에코 흐름
클라(node0) 1024B → 서버(node1) 도착 → 바로 되돌려 보냄 → node0 수신, 로그 찍힘.


B. week4_ex2_onoff_app.cc – CBR 발사기

슬라이드 24–25에 해당.

1~4단계는 똑같음 (노드·링크·IP까지 동일)

5단계 ‑ OnOffApplication 생성

uint16_t port = 9;
OnOffHelper onoff("ns3::UdpSocketFactory",
  Address(InetSocketAddress(Ipv4Address("10.1.1.2"), port)));

onoff.SetAttribute("OnTime",
   StringValue("ns3::ConstantRandomVariable[Constant=1]"));
onoff.SetAttribute("OffTime",
   StringValue("ns3::ConstantRandomVariable[Constant=1]"));
onoff.SetAttribute("DataRate", DataRateValue("5Mbps"));   // CBR 속도

ApplicationContainer app = onoff.Install(terminals.Get(0)); // node0
app.Start(Seconds(1));
app.Stop (Seconds(10));
  • 1초 On / 1초 Off 반복.
  • DataRate 5 Mbps, PacketSize(디폴트 512B) → 초당 약 1 k패킷쯤.

6단계 ‑ PacketSink(node1)

PacketSinkHelper sink("ns3::UdpSocketFactory",
  Address(InetSocketAddress(Ipv4Address::GetAny(), port)));

sink.Install(terminals.Get(1)).Start(Seconds(1));

7단계 ‑ 15초에 시뮬 종료

Simulator::Stop(Seconds(15));   // 몇 초 더 넉넉히
Simulator::Run();
Simulator::Destroy();

결과
node1 PacketSink 가 “Received xxx bytes” 스팸처럼 찍어준다.
PCAP 안 켰으니 필요하면 p2p.EnablePcapAll(...) 추가.

 

 

핵심만 머리에 박아!


1 nodes.Create(2);
2 PointToPointHelper 로 속도/딜레이 세팅 → Install()
3 InternetStackHelper + Ipv4AddressHelper
4 App Helper 붙이고 Start/Stop 시간만 지정
5 필요하면 EnablePcapAll() 딱 한 줄

 

 

최종정리

 

1. Command‑Line Args
(CommandLine cmd; … AddValue)
‑ C++ 소스 뜯어 고치지 말고, 실행 시 옵션으로 파라미터 집어넣어라
  → 시뮬 돌릴 때  ./waf --run "myfirst --howmany=2 --delay=10ms" 같은 식
2. Tracing System & PCAP ‑ EnablePcapAll() 한 줄이면 패킷 캡처(.pcap) 자동 생성
‑ tcpdump ‑nn -tt -r file.pcap or Wireshark로 바로 확인
3. ns‑3 Application 카달로그 ‑ 이미 구현된 4대 천왕:
  1) OnOffApplication (CBR 발사·휴식)
  2) PacketSink (받고 끝)
  3) UdpEcho (Client/Server) (핑퐁)
  4) UdpClient / UdpServer (클라→서버 단방향)
4. Helper + Attribute 패턴 ‑ 무조건 *_Helper helper; → helper.SetAttribute("Foo", ...) → helper.Install(node)
‑ Attributes= 데이터레이트, 패킷사이즈, Interval… 실험값만 쓱 갈아끼우면 끝
5. Application 수명주기 ‑ Start(Time) / Stop(Time) = 이벤트 스케줄링
‑ 실행 중간에 Simulator::Run() 한방이면 타임라인대로 다 처리
6. Example 2 코드
(Echo & OnOff)
‑ P2P 링크 만들기 → IP 부여 → App 올리기 3‑Step 템플릿 시연
‑ Echo 예제: 끊임없이 핑·퐁 확인
‑ OnOff 예제: 1 초 On / 1 초 Off CBR 패턴 보여주기
반응형
LIST