개발놀이터

패킷 한 조각의 모험 : 네트워크 속 비밀 이야기 본문

CS 지식/네트워크

패킷 한 조각의 모험 : 네트워크 속 비밀 이야기

마늘냄새폴폴 2024. 11. 18. 21:50

우리가 파일을 다운로드 하는 경우는 정말 흔하게 일어나죠. 그 중에서 이번 포스팅에선 TCP프로토콜을 이용해서 파일을 다운로드 하는 경우에 패킷이 어떤 흐름으로 이동하는지에 대해서 공부해보고 정리해봤습니다!

 

패킷 한 조각의 모험, 바로 시작해보겠습니다!

 

패킷의 여행

보통 대부분의 네트워크는 TCP/IP 프로토콜을 이용하는 것으로 알고 있습니다. 때문에 이번 포스팅에서도 TCP프로토콜에 한정하여 이야기해보도록 하겠습니다. 

 

서버는 우리 컴퓨터와 네트워크로 연결하기 위해 TCP/IP 프로토콜을 사용합니다. 서버는 TCP연결을 위해 소켓을 여는데 이 소켓은 유닉스 체계에서 파일로 이루어져 있습니다. 

 

파일을 들고 있는 서버는 웹 서버라고 한다면 이 웹 서버는 프로세스 위에서 동작합니다. 즉, 추상화 해보면 프로세스가 파일을 만든다고 해석할 수 있겠네요. 

 

이것과 관련된 포스팅 내용을 최근에 작성했습니다! 한번 보고 오셔도 괜찮을 것 같네요. 

 

https://coding-review.tistory.com/568

 

TCP 프로토콜을 OS레벨에서 뜯어보자

TCP프로토콜은 전세계적으로 가장 많이 사용되는 프로토콜 중 하나인데요. 이 TCP프로토콜이 OS레벨에서는 어떻게 움직이는지 살짝 궁금해져서 공부해보고 정리해봤습니다!  OS레벨에서 개요를

coding-review.tistory.com

 

프로세스가 파일에 접근해서 할 수 있는건 RWX (Read, Write, Execute) 이렇게 세 가지가 일반적일겁니다. 

 

그 중에서 소켓 통신의 경우 R과 W를 주로 하는데 소켓 통신에서 R은 Read가 아닌 Receive라고 표현하고 W는 Write가 아닌 Send라고 표현합니다. 

 

1. 파일 입출력

서버에 존재하는 파일은 분명 물리적인 저장소에 존재하고 있을 것입니다. HDD나 SSD에 저장되어 있겠죠? 

 

운영체제는 HDD나 SSD에 존재하는 실제 파일을 파일 입출력을 이용해서 메모리에 적재합니다. 이 과정을 담은 포스팅 또한 준비되어 있습니다. 

 

https://coding-review.tistory.com/563

 

데이터베이스 쿼리를 실행하면 내부적으로는 어떤 일이 벌어질까?

오랜만에 포스팅을 쓰는 것 같습니다. 거의 열흘만인 것 같은데 요즘 쿠버네티스를 공부하느라고 실습을 위주로 공부하고 있느라 공부할 시간이 마땅히 나지 않았네요...  이번 포스팅은 평소

coding-review.tistory.com

 

데이터베이스의 내용이 조금 들어가있긴 하지만 주 내용은 운영체제에 대한 내용이니 보고 오셔도 좋을 것 같습니다!

 

우리는 2MB짜리 파일을 다운받는다고 가정해보죠. 그럼 운영체제가 메모리를 2MB를 준비하느냐? 

 

그건 아닙니다. 

 

만약 그랬다간 서버에 메모리가 금방 부족해질 것입니다. 

 

2MB보다 작은 64KB로 준비해놓는다고 가정해봅시다. (이 값은 프로그래머가 적절히 개발해놓는 값입니다.) 

 

2MB짜리 파일이 64KB의 메모리 위에 잘개 쪼개져서 운반되었습니다. 이제 다음으로 넘어가보죠. 

 

2. TCP/IP 프로토콜의 Encapsulation

프로세스의 메모리 위에 올라와있는 64KB의 파일 조각들은 TCP 프로토콜에 존재하는 메모리에 복사가 됩니다. 이 포스팅에서는 TCP메모리라고 칭할 것입니다. 

 

이렇게 메모리에서 메모리로 데이터가 이동하는 것을 Buffered I/O라고 부릅니다. 자바에서는 BufferedInputStream, BuffredOutputStream으로 유명하지요. 이 두가지의 동작 방식이 바로 Buffered I/O 입니다. 

 

TCP메모리 위에 올라와있는 64KB의 파일을 Segment라는 가장 작은 단위로 쪼개서 프레임이라는 곳에 담아냅니다. 이 때 Segment가 바로 우리가 잘 알고 있는 "패킷"입니다. 앞으로 Segment를 패킷이라고 칭하겠습니다. 

 

이 패킷은 프레임이라는 곳에 담겨서 이제 본격적으로 이동하게 됩니다. 

 

이를 보통 택배와 택배기사로 비유를 많이 드는데요. 

 

출처 : 본인

 

이렇게 프레임이 택배차에 담겨서 이동하게 됩니다. 

 

이 택배차의 용도는 택배를 전달하는데 있습니다. 여기서 중요한 것은 택배기사한테 택배를 전달했다고 해서 이 택배가 택배기사의 것이 되는 것이 아니라는 것입니다. 

 

택배기사는 이 택배물을 자신이 이동시켜야할 위치까지 이동시키는 것에 목적을 둡니다. 

 

여기서 잠깐!

 

이 택배가 우리집까지 오기까지 택배차가 바뀔까요? 안바뀔까요? 

 

바뀔수도, 안바뀔수도 있습니다. 

 

현실에 빗대어보면 택배차가 바뀌는 것이 조금 더 일반적인 것인데, 우리가 시킨 택배는 생산지로부터 우리집 근처의 허브까지 이동하게 되고 이 허브에서 다시 우리집으로 오게 되는 과정을 생각해보면 택배 차가 바뀌게 되는게 조금 더 일반적이죠. 

 

네트워크의 흐름에서도 패킷이 프레임에 담겼다가 풀어졌다가 다시 담겼다가를 반복합니다. 

 

패킷의 흐름은 논리적으로는 엔드 투 엔드로 이동하게 되지만 그 과정에서 끝에 있는 엔드포인트가 최종 목적지가 아닐 수도 있다는 것입니다. 

 

3. 택배가 우리집에 오기까지

이 택배는 L7계층인 서버의 애플리케이션에서부터 L4계층인 TCP를 타고 캡슐화가 진행되었습니다. 

 

그리고 이 패킷이 네트워크를 타고 우리집에 오게 되는데 L4에서 흐르던 패킷은 L3인 라우터에 도달합니다. 라우터로 가장 유명한 것은 바로 공유기이죠. 

 

공유기에 우리가 받을 패킷이 도착하게 되면 이제 L2계층인 스위치로 이동합니다. 집에 보통 스위치가 있는 경우도 있고 없는 경우도 있지만 만약 있다면 스위치는 이 패킷에 적혀있는 MAC주소를 보고 알맞은 기기에 전달해줍니다. 

 

PC에는 NIC이라는 것이 있습니다. Network Interface Card의 약자이죠. NIC도 우리가 잘 알고 있습니다. 바로 메인보드에 박혀있는 LAN카드가 바로 NIC입니다. 이 랜카드가 바로 L1계층입니다. 이제 Decapsulation이 일어나게 됩니다. 

 

이를 도식화하면 다음과 같습니다. 

 

출처 : 본인

 

4. Decapsulation

패킷이 클라이언트의 PC에 도착하면 Decapsulation이 일어나고 이 패킷들이 클라이언트의 TCP메모리에 적재됩니다. 그리고 아까와 마찬가지로 TCP메모리에 있는 패킷이 클라이언트의 파일시스템에 할당된 메모리에 적재됩니다. 

 

이 파일 시스템의 메모리는 패킷으로 받은 데이터를 실제 물리 저장소에 저장합니다. 

 

이렇게 TCP메모리에 패킷을 잘 적재하면 클라이언트는 서버에게 패킷을 잘 받았다는 의미로 ACK 신호를 보내게 됩니다. 만약 1번 2번 패킷을 받았다면 ACK 신호를 보내면서 다음 패킷 번호를 보내줍니다. 여기선 3번이 되겠네요. 

 

이 말은 다시 말해서 1, 2번 잘 받았으니까 다음은 3번 내놓으라는 의미입니다. 

 

이 과정에서 서버는 뭘 하고 있을까요? 

 

5. 형님 한 번, 아우 한 번

서버는 클라이언트에게 ACK 신호를 받을때까지 무한정 대기하고 있습니다. 

 

엥..? 진짜 무한정 대기..?

 

이것이 TCP가 UDP보다 속도가 느리다고 말하는 수 많은 이유 중 하나이며 이 뒤에 또 한가지 이유가 더 나옵니다. 

 

클라이언트가 ACK신호를 보낼 때 전송하는 값 중에서 다음 패킷 번호도 있지만 클라이언트 자신의 TCP메모리의 크기도 같이 보내줍니다. 이 크기를 같이 보내주는 이유는 서버가 다음 패킷을 보내야하는데 클라이언트의 TCP메모리가 꽉차있으면 다음 패킷을 보낼 수 없기 때문입니다. 

 

만약 꽉 차있지 않으면 서버는 다음 패킷을 보냅니다. 하지만 만약 꽉 차있다면요? 

 

서버는 클라이언트에게 패킷을 보낼 수 없다는 신호를 다시 보내게됩니다. 

 

지금 패킷은 이동조차 하지 못했습니다. 서버는 ACK신호를 보낼 때까지 기다리고 있었고 기다리다가 ACK신호를 받았는데 이놈의 클라이언트 TCP메모리가 꽉차서 패킷을 못보내니까요. 

 

이제 클라이언트는 TCP메모리를 동적으로 늘리게 되고 이제 보내도 좋다는 신호를 자신의 TCP메모리의 크기와 함께 다시 보내줍니다. 

 

그 상태에서 서버가 클라이언트의 TCP메모리를 확인하고 패킷을 보내게 됩니다. 

 

이거 어디서 많이 본 그림인데... 

 

맞습니다. 바로 TCP/IP하면 조건반사로 튀어나오는 바로 그것! "흐름제어"입니다. 그리고 흐름제어에서 나오는 Sliding Window라고 표현하는 그것에서 알 수 있듯이 클라이언트의 TCP메모리를 "Window"라고 부릅니다. 

 

이것에 대해서 깊이있게 공부하고 정리한 포스팅이 있습니다! 

 

https://coding-review.tistory.com/466

 

네트워크 흐름제어와 혼잡제어 (Flow Control, Congestion Control)

우리가 흔히 말하는 네트워크 통신은 TCP 3way handshaking에 의해 일어납니다. 그리고 TCP에 대해 조금 공부해보신 분들은 UDP와의 차이도 말할 수 있죠. UDP와 다르게 TCP는 전이중 방식과 점대점 방식

coding-review.tistory.com

 

이 글에 자세히 정리되어 있습니다. 

 

6. 해치웠나..?

클라이언트에게 계속 패킷이 들어오긴 하는데 만약 파일 시스템에 할당된 메모리로 적재되는 속도보다 패킷이 TCP메모리에 적재되는 속도가 더 빠르다면 어떻게 될까요? 

 

즉, 파일 시스템에 저장하는 속도보다 내 PC로 들어오는 네트워크 속도가 더 빠르면 말이죠. 

 

이렇게 되면 또 다시 네트워크 지연이 발생할 수 있습니다. 정말 끝도 없네요. 왜 TCP가 UDP보다 느리다고 하는지 이제서야 알 것 같습니다. 

 

때문에, TCP프로토콜에서는 보내는 쪽의 컴퓨팅 성능이 네트워크 지연을 야기하는 것이 아니라 받는 쪽의 컴퓨팅 성능이 네트워크의 지연을 야기합니다. 

 

보통의 경우 받는 쪽의 CPU에 부하가 생겨서 메모리를 빠르게 비우지 못하는 경우이거나 아니면 클라이언트의 애플리케이션이 파일 입출력을 하는 속도가 느린 경우가 대부분입니다. 

 

마치며

이렇게 패킷의 여행에 대해서 알아봤습니다. 뭔가 세상의 이치를 알게된 느낌이라 정말 머리가 개운하고 좋습니다. 요즘은 이런 공부가 좀 재밌는 것 같아요.

 

CS공부가 실전에서 아직은 크게 도움되지는 않습니다. 하지만 혹시 모르죠! 나중에 정말 중요한 곳에 쓰이게 될지말이에요. 그 날을 기대하면서 CS공부를 꾸준히 해야겠네요. 

 

긴 글 읽어주셔서 감사합니다! 오늘도 즐거운 하루 되세요~