
second.cc는 P2P와 LAN이 결합된 네트워크 토폴로지이다.
n0 과 n1노드가 P2P로 연결되고, n2 n3 n4노드는 n1과 LAN으로 통신하는 네트워크 노드이다.
전체 코드 보기
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("SecondScriptExample");
int
main(int argc, char* argv[])
{
bool verbose = true;
uint32_t nCsma = 3;
CommandLine cmd(__FILE__);
cmd.AddValue("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma);
cmd.AddValue("verbose", "Tell echo applications to log if true", verbose);
cmd.Parse(argc, argv);
if (verbose)
{
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
}
nCsma = nCsma == 0 ? 1 : nCsma;
NodeContainer p2pNodes;
p2pNodes.Create(2);
NodeContainer csmaNodes;
csmaNodes.Add(p2pNodes.Get(1));
csmaNodes.Create(nCsma);
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute("DataRate", StringValue("5Mbps"));
pointToPoint.SetChannelAttribute("Delay", StringValue("2ms"));
NetDeviceContainer p2pDevices;
p2pDevices = pointToPoint.Install(p2pNodes);
CsmaHelper csma;
csma.SetChannelAttribute("DataRate", StringValue("100Mbps"));
csma.SetChannelAttribute("Delay", TimeValue(NanoSeconds(6560)));
NetDeviceContainer csmaDevices;
csmaDevices = csma.Install(csmaNodes);
InternetStackHelper stack;
stack.Install(p2pNodes.Get(0));
stack.Install(csmaNodes);
Ipv4AddressHelper address;
address.SetBase("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = address.Assign(p2pDevices);
address.SetBase("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = address.Assign(csmaDevices);
UdpEchoServerHelper echoServer(9);
ApplicationContainer serverApps = echoServer.Install(csmaNodes.Get(nCsma));
serverApps.Start(Seconds(1.0));
serverApps.Stop(Seconds(10.0));
UdpEchoClientHelper echoClient(csmaInterfaces.GetAddress(nCsma), 9);
echoClient.SetAttribute("MaxPackets", UintegerValue(1));
echoClient.SetAttribute("Interval", TimeValue(Seconds(1.0)));
echoClient.SetAttribute("PacketSize", UintegerValue(1024));
ApplicationContainer clientApps = echoClient.Install(p2pNodes.Get(0));
clientApps.Start(Seconds(2.0));
clientApps.Stop(Seconds(10.0));
Ipv4GlobalRoutingHelper::PopulateRoutingTables();
pointToPoint.EnablePcapAll("second");
csma.EnablePcap("second", csmaDevices.Get(1), true);
Simulator::Run();
Simulator::Destroy();
return 0;
}
디버깅 관련 코드
bool verbose = true;
uint32_t nCsma = 3;
CommandLine cmd(__FILE__);
cmd.AddValue("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma);
cmd.AddValue("verbose", "Tell echo applications to log if true", verbose);
cmd.Parse(argc, argv);
if (verbose)
{
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
}
nCsma = nCsma == 0 ? 1 : nCsma;
처음 선언하는 verbose와 nCsma는 디버깅 기능 파헤치기 편에서 언급했던 변수값 변경 디버깅,
즉 cmd.AddValue()에 사용되는 변수이다.
cmd에서 run명령어로 코드를 실행할 때, 특정 옵션을 같이 입력하여 위 두 변수를 변경할 수 있다.
verbose는 '장황한' 이라는 단어로, 디버깅 로그를 출력하게 할지를 결정하는 변수라고 보면 된다.
nCsma는 뒤에서 설명하겠지만, Csma 링크 (LAN)에 포함되는 노드의 개수를 표현한다.
기본으로 3을 설정하지만 0인지 확인하고 최소 1을 가지게 하는것은 cmd 명령 입력으로 값이 바뀔 수 있기 때문이다.
하지만 말 그대로 디버깅용 코드이기때문에,
기능을 분석하는 입장에서는 기본값으로는 true와 3을 가지고 있다는것만 기억하면 될 것 같다.
노드 생성 및 Install
NodeContainer p2pNodes;
p2pNodes.Create(2);
NodeContainer csmaNodes;
csmaNodes.Add(p2pNodes.Get(1));
csmaNodes.Create(nCsma);
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute("DataRate", StringValue("5Mbps"));
pointToPoint.SetChannelAttribute("Delay", StringValue("2ms"));
NetDeviceContainer p2pDevices;
p2pDevices = pointToPoint.Install(p2pNodes);
CsmaHelper csma;
csma.SetChannelAttribute("DataRate", StringValue("100Mbps"));
csma.SetChannelAttribute("Delay", TimeValue(NanoSeconds(6560)));
NetDeviceContainer csmaDevices;
csmaDevices = csma.Install(csmaNodes);
InternetStackHelper stack;
stack.Install(p2pNodes.Get(0));
stack.Install(csmaNodes);
first.cc와 같이, 일단 p2p용 노드 2개를 생성한다.
이후 이번에는 p2p용 노드중에 하나(n1)를 csma용도로도 설정하고(Add)
나머지 3개(기본)의 csma용 노드를 생성한다.
p2p링크 노드들에는 지난번과 같은 데이터율과 딜레이를 설정하고, p2p 디바이스에 노드를 추가한다.
csma링크 노드들에는 또 다른 설정을 적용하고, csma 디바이스에 노드를 추가한다.
즉, n1노드는 현재 두가지 장치에 설치되어있다.
이후 인터넷 스택을 install하는데, n1은 csma노드이면서 p2p노드이므로 중복 설치가 되지 않게끔 주의한다.
주소 할당 및 포트 연결
Ipv4AddressHelper address;
address.SetBase("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = address.Assign(p2pDevices);
address.SetBase("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = address.Assign(csmaDevices);
UdpEchoServerHelper echoServer(9);
만들어진 디바이스에 각각 토폴로지에 따라 주소를 할당하고, 9번포트를 echoSever로 연다.
서버 , 클라이언트 노드 지정
ApplicationContainer serverApps = echoServer.Install(csmaNodes.Get(nCsma));
serverApps.Start(Seconds(1.0));
serverApps.Stop(Seconds(10.0));
UdpEchoClientHelper echoClient(csmaInterfaces.GetAddress(nCsma), 9);
echoClient.SetAttribute("MaxPackets", UintegerValue(1));
echoClient.SetAttribute("Interval", TimeValue(Seconds(1.0)));
echoClient.SetAttribute("PacketSize", UintegerValue(1024));
ApplicationContainer clientApps = echoClient.Install(p2pNodes.Get(0));
clientApps.Start(Seconds(2.0));
clientApps.Stop(Seconds(10.0));
이후 server를 담당할 노드의 serverApps를 만드는데, 이때 Csma노드의 가장 오른쪽 끝 노드(10.1.2.4)를 서버노드로 지정한다.
클라이언트 app은 당연히 n0노드로 설정한다.

라우팅 테이블 생성 및 시뮬 실행
Ipv4GlobalRoutingHelper::PopulateRoutingTables();
pointToPoint.EnablePcapAll("second");
csma.EnablePcap("second", csmaDevices.Get(1), true);
Simulator::Run();
Simulator::Destroy();
return 0;
이번에는 LAN환경이 추가되어 라우터를 통한 포워딩이 이루어지므로, 라우터를 위한 라우팅테이블을 초기화하여 생성해준다.
이후 Pcap이라는것을 활성화하여, p2p장치의 모든 패킷과 n2(csma장치의 2번째 노드)를 지나는 모든 패킷을 캡쳐한다.
EnablePcap의 마지막 인자로 넘기는 true는 "promiscuous"라는 파라미터의 인자값으로, 이것이 활성화 되면 사실 본인에게 향하는 패킷 뿐 아니라 본인이 속한 네트워크 세그멘트에서 일어나는 모든 브로드캐스트 통신을 캡쳐한다.
마지막으로 시뮬레이터를 돌리고, Destroy한다.
Pcap 확인
Pcap은 패킷 캡쳐(Packet Capture)로, 특정 노드(장치)를 끼고 일어나는 패킷 전송 로그를 기록한다.
<이름> <노드번호> - <장치번호>의 의미를 가지고, 확장자명은 .pcap이다.
**n1과 같이 두 개의 장치를 가진 노드라면, 1-0, 1-1 두 개의 파일이 생성된다.

EnablePcap은 p2p장치와 n2 노드를 기준으로 했기 때문에, (n0, n1), n2노드에 대한 패킷캡쳐 파일만 생성된다.
당연히 더블클릭으로 열어서 볼 수 없고, 아래 명령어를 통해 내용을 볼 수 있다.
$ tcpdump -nn -tt -r <파일이름.pcap>

n0에서 송수신된 패킷은, server로 보낸 패킷과, server에서 받은 패킷만 존재한다.

n1도 p2p로 이어져있으므로, 위에서 기록된것과 동일한 패킷이 본인을 타고 지나갔음을 기록해놓았다.

n2는 csma 링크의 LAN환경에서의 패킷 로그를 담고있다.
같은 LAN 네트워크의 통신이므로, n1노드(10.1.2.1)와 n4노드(10.1.2.4)간 ARP를 날리는 것이 기록되어있다.
원래 통신의 주체는 클라이언트인 n0과 서버인 n4이지만, 서로 다른 네트워크에 속하기때문에,
p2p로 연결된 n1노드에게 주소를 가져와달라 ARP요청을 보내고,
n1은 그 요청을 reply하기 위해 같은 네트워크 안의 노드들에게 ARP를 또 날리게 되는 것이다.

클라이언트가 보낸 request가 echo인것을 서버(n4)가 확인하고,
정확히 반대의 과정으로 클라이언트(n0)에게 echo reply 패킷(1024바이트)을 전송한다

컴퓨터 네트워크 수업시간에 배운 내용을 실제로 시뮬레이션 하는 느낌이 들어, 재밌게 분석해본 코드였다.
'개인공부' 카테고리의 다른 글
| [MQTT / Python / IoT] LCFS Queue 구현 (0) | 2025.12.26 |
|---|---|
| [MQTT / Python / IoT] Python으로 구현하는 MQTT (0) | 2025.12.01 |
| [NS-3] α. NS-3 디버깅 기능 파헤치기 (0) | 2025.11.21 |
| [NS-3] 1. first.cc 해체 분석 (0) | 2025.11.20 |
| [NS-3] 0. 시작하기 (0) | 2025.11.19 |