March 5th 2020
Contents
Network Basics
네트워크 인터페이스층(데이터 링크층)
The Basics of Networking Devices
Ping to Http
Names and Addresses
Addressing and Networks
Protocol Layers
오늘날 우리가 사용하는 컴퓨터는 또다른 컴퓨터와의 상호작용을 빼놓고 이야기 할 수 없어요. 랩탑이나 태블릿, 스마트폰은 어떠한 방식으로든 연결되어 있으며, 서로 통신합니다.
저는 네트워킹이 기본적으로 어떻게 작동하는지 알지 못한채 컴퓨터를 이용하지만, 네트워킹의 근간을 이해하면 어떠한 일을 하던지 여러면에서 더 성공할 확률이 높아질 것이라고 생각해요.
네트워크 또는 정보 통신에서 '프로토콜'이란 말을 많이 사용해요. 프로토콜은 컴퓨터와 컴퓨터가 네트워크를 이용해 통신하기 위해 정해 놓은 '약속'이라고 할 수 있어요. 대표적인 프로토콜로는 IP, TCP, HTTP를 들 수 있습니다.
현재 많은 기기에서 TCP/IP 를 이용하지만 Novel사가 개발하고 LAN에서 주로 사용하는 IPX/SPX, Apple사 컴퓨터에서 사용되던 Apple Talk 등도 있다고 하네요.
네트워크 연결을 설정할 때를 제외하고는, 우리가 애플리케이션을 사용할 때 프로토콜을 의식해야 하는 경우는 많지 않습니다. 하지만, 네트워크를 이용한 커뮤니케이션을 하기 위해서는 프로토콜의 존재에 대해 알아야 합니다. 제조업체나 CPU , OS가 다른 컴퓨터끼리도 같은 프로토콜을 사용하면 서로 통신할 수 있습니다. 반대로, 같은 프로토콜을 사용하지 않으면 서로 통신할 수 없어요.
사람은 응용력, 이해력을 가지고 있기 때문에 어느정도 규칙에서 벗어나거나 대화 중 말을 놓쳐도 의사 소통이 가능해요. 하지만 컴퓨터는 커넥터의 모양과 같은 물리적인 레벨부터 소프트웨어 레벨에 이르기까지 분명한 약속을 정하고, 이를 지키는 것이 중요합니다.
컴퓨터가 통신할 때 전송할 데이터를 패킷으로 분할하여 보냅니다. 패킷의 헤더에는 자신의 주소, 상대방의 주소, 데이터 번호가 기록되어 있습니다. 통신 프로토콜에는 헤더에 기록된 정보를 어떻게 처리할지가 정해져 있습니다. 따라서, 컴퓨터는 프로토콜에 따라 헤더를 작성하고 헤더의 내용을 해독합니다.
ISO는 통신 프로토콜의 설계 지표로서 OSI 참조 모델을 제안했습니다. OSI 참조 모델은 통신에 필요한 기능을 7개의 계층으로 나누어 네트워크 프로토콜을 단순화한 것입니다. 프로토콜의 계층화는 소프트웨어의 모듈화와 비슷합니다.
현재 TCP/IP는 가장 많이 사용하는 네트워크 프로토콜입니다. 네트워크를 구축/관리하는 사람, 네트워크 기기를 설계/제조하는 사람, 네트워크 연결된 기기를 프로그래밍하는 사람은 TCP/IP에 대한 지식을 갖추어야 합니다. TCP/IP에 나오는 각종 프로토콜도 기본적으로 OSI 참조 모델에 적용시킬 수 있습니다. 각 프로토콜이 OSI 참조 모델의 어느 층에 해당하는지를 알면, 그 프로토콜이 무엇을 하기 위한 것인지 짐작할 수 있습니다. 그 다음 기술적으로 어떤 구조로 작동하는지 이해하면 됩니다.
물리층에서는 한 지점에서 다른 곳으로 0과 1을 통해 데이터를 전송해주는 장치가 있습니다. 0과 1은 데이터를 구성하는 프레임과 패킷을 나타냅니다. 그것이 음악이 되었던, 이메일이던 또는 ATM을 사용할 때이건 상관없이 0과 1로 전송이 됩니다. 0과 1로 전송이 되는 한 프로세스를 modulation(변조)라 합니다. 그리고 이것이 컴퓨터 네트워크를 위해 사용될 때는 line coding이라 부릅니다. line coding이라니 말이 멋스럽네요. 이를 통해 디바이스가 전압을 받아 0인지 1인지를 구분할 수 있도록 합니다.
Twisted Pair Cabling
컴퓨터를 연결하는데 가장 일반적인 케이블 타입은 TP(twisted pair)입니다. 이 TP는 단일 전달자(conduit) 역할을 하며, crosstalk과 전자기적 외부 영향을 방지합니다. 중요한 점은, 이 TP가 이중통신(duplex communication)을 가능하게 한다는 점입니다. 참고로, simplex communication은 단방향 통신입니다. 케이블이 양방향 통신을 하는 방법은 케이블 안의 여러 페어들 중 1개 내지 2개 페어를 한 쪽에서 예약하고, 나머지 페어를 반대측에서 예약하는 방식으로 이루어집니다. 연결에 문제가 생기면 반이중 통신(half-dplex)으로 변경되는데, 이는 한번에 한쪽에서만 통신이 가능하게 합니다.
Network Ports and Patch Panels
물리층 프로세스의 마지막 단계는 네트워크 링크의 끝부분에서 이루어집니다. TP 케이블의 끝은 플러그로 되어있습니다. 가장 일반적으로 사용되는 플러그와 포트는 Rj-45입니다. Rj-45 플러그는 Rj-45 플러그와 연결을 할 수 있는데, 이 플러그는 컴퓨터 네트워크를 구성하는 디바이스에 연결됩니다. 대부분의 포트는 link light와 activity light는 가지고 있습니다. lnk light는 두 디바이스가 켜져있고 접속이 원활히 된 상태를 나타냅니다. Activity light는 케이블 간 데이터 전송이 될 때 깜빡입니다. 이전에는 실제 0과 1이 전송됨을 나타냈지만, 오늘날에는 속도가 워낙 빨라서 트랙이 있는지를 주로 표시합니다.
포트가 실제 디바이스에 직접 연결되지 않는 경우도 있습니다. 사무실이나 방안의 벽에 있는 포트를 떠올려 볼 수 있습니다. 이 포트는 실제 디바이스와 연결되지 않고 Patch Panel에 연결됩니다. Patch Panel은 여러 포트를 가지고 있는 컨테이너의 역할만 합니다. 각 포트가 네트워크에 연결될 수 있도록 스위치나 라우터로 연결해 줍니다.
요즘은 모바일 또는 무선 인터넷을 많이 사용하지만, 그래도 아직까지 사무실이나 데이터센터에서 주로 사용하는 방식은 케이블입니다. 그리고, 개별 링크에서 데이터를 보내기 위해 가장 많이 사용되는 프로토콜은 이더넷입니다. 데이터링크층은 상위 층이 물리층과 하드웨어에 대해 신경 쓰지 않고도 자신들의 작업을 할 수 있도록 추상화하는 밑바탕 작업을 합니다.
네트워크 인터페이스층은 이더넷과 같은 데이터링크를 이용해 통신을 하기 위한 인터페이스가 되는 계층입니다. 즉, NIC(Network Interface Controller)를 작동시키기 위한 '디바이스 드라이버'라고 생각할 수 있습니다. 드라이버란 OS와 하드웨어를 이어주는 소프트웨어 입니다. 예로, 브라우저는 디바이스가 TP 케이블로 네트워크에 연결된 상태인지 무선인터넷을 사용하고 있는 상태인지에 대한 것을 알 필요가 없습니다.
이더넷은 1980년대부터 사용되었으며, 당시의 인터넷 환경은 지금과는 많이 달랐습니다. 주요한 차이점은 당시에 스위치나 허브가 나오기 전이었다는 것입니다. 즉, 네트워크 상 많은 디바이스가 Collision Domain 상태를 많이 겪었다는 것을 의미합니다.
Collision Domain이란 한번에 한 디바이스만 통신을 할 수 있는것을 말합니다. 이는 곳 데이터 충돌로 이어져 예상치 못 한 결과를 발생시킵니다. 이더넷은 CSMA/CD(Carrier Sense Multiple Access with Collision Detection)라는 기술을 도입해 이 문제를 해결했습니다. CSMA/CD는 통신 채널이 데이터를 전송 가능한 상태인지 체크하는데 사용됩니다.
Collision Domain 상태에서는 네트워크 상 모든 디바이스가 모든 통신을 수신하고 있는것을 의미합니다. 따라서, 각 통신이 정확히 어떠한 노드를 위한 것인지 알아낼 필요성이 생겼습니다. 이러한 배경으로 MAC(Media Access Control) 주소가 등장하게 됩니다.
맥 주소의 첫 세 옥텟은 OUI(Organizationally Unique Identifier)로 알려졌으며, IEEE(The Institute of Electrical and Electronics Engineers)에 의해 각 하드웨어 제조업체에 부여됩니다. 때문에, 우리는 MAC 주소 만으로도 네트워크 인터페이스의 제조업체를 파악할 수 있습니다. 마지막 세 옥텟은 세계적으로 유니크한 주소가 된다는 전제하에 제조업체가 부여합니다. 이더넷은 MAC 주소를 이용해 전달할 데이터의 송신처와 수신처를 확실히 합니다.
아래에서는 이더넷 프레임에서 나오는 개념들에 대해 정리하고 넘어가려 합니다.
Ethernet Frame
Data Packet이란 네트워크 상에서 바이너리로 이동하는 데이터 단위를 나타냅니다. 특정 Layer나 기술에서만 사용하는 것이 아니고 범용적인 용어입니다. 그리고 이더넷 레벨에서의 패킷을 Ethernet Frame
이라 합니다. 이더넷 프레임은 정해진 규칙과 순서에 맞게 구조화 돼 있어서, 물리층에서 이를 이해할 수 있도록 합니다. 대부분의 섹션은 필수적이며 사이즈 또한 정해져있습니다.
이더넷 프레임의 맨 앞은 프리앰블(Preamble)이라는 필드가 있습니다. 프리앰블은 8바이트 또는 64비트로 돼 있고, 첫 7 바이트는 1과 0 이 교대로 나열됩니다. 이는 프레임 간 버퍼로도 사용할 수 있고, 네트워크 인터페이스가 내부 시계를 동기화 하거나 데이터 전송 속도를 조절할 때에도 사용할 수 있습니다.
프리앰블의 마지막 바이트는 SFD(Start Frame Delimiter)라 하며, 수신 디바이스에 프리앰플이 끝나고 실제 프레임 콘텐츠가 시작된다는 신호로 사용됩니다. SFD 다음으로 48비트, 6바이트 길이의 MAC 주소가 옮니다. 그리고, 그 다음에는 EtherType이라 불리는 16비트 길이의 필드가 오는데, 이는 프레임 콘텐츠의 프로토콜을 나타내는데 사용됩니다. 뒤쪽에서 좀 더 상세히 알아보도록 하겠습니다.
로컬 네트워크 상에서 node 간 MAC 주소를 통해 쉽게 통신할 수 있습니다. 이는 작은 규모에서 트랙픽을 전달하기 위해 각 포트에 연결된 MAC 주소를 쉽게 찾을 수 있기 때문입니다. 하지만, MAC 주소는 확장성이 좋지 않습니다. 전 세계의 모든 네트워크 인터페이스는 MAC 주소를 가지고 있지만, 어떠한 체계를 가지고 정리되어 있지는 않습니다. 특정 MAC 주소가 전 세계의 어느 위치에 있는지 알 수 있는 방법은 없기 때문에, 원거리 간 통신을 하기 적합하지 않습니다. 이를 위해 네트워크 층이 존재합니다.
IP 주소는 어떠한 단체나 회사 등 MAC 주소보다 좀 더 포괄적인 범위로 분포되어 있습니다. 예를 들어, IBM의 경우 9로 시작하는 모든 IP 주소를 가지고 있습니다. 어떠한 라우터가 IP 주소 9.0.0.1로 패킷을 전달해야 한다면, 해당 라우터는 IBM의 라우터 중 하나로 패킷을 전달하면 된다는 것을 쉽게 알 수 있습니다.
밑에서도 다시 설명하겠지만, IP 주소는 디바이스에 종속된 것이 아니라, 네트워크 인터페이스에 종속된 것이라고 봐야합니다. 우리가 사용하는 랩탑은 항상 같은 MAC 주소를 가지고 있습니다. 하지만 카페에서 사용할 때와 집에서 사용할 때의 IP 주소는 다를 것입니다. 이때의 IP 주소는 카페의 LAN 또는 집의 LAN이 할당합니다.
인터넷층에서는 IP 프로토콜을 사용해, IP 주소를 바탕으로 패킷을 전송합니다. TCP/IP 계층 모델에서는 일반적으로 인터넷층과 트랜스포트층이 OS에 내장되어 있다고 전제합니다. IP(Internet Protocol)은 네트워크를 통해 패킷을 전달하기 위한 프로토콜이며, 각 호스트를 식별하기 위해 IP 주소라는 식별자를 이용합니다. IP에는 데이터링크의 특성을 감추는 역할도 있어, 어떤 데이터링크로 되어 있는지 상관없이 통신이 가능합니다. 패킷이 상대방에게 도착하지 않은 경우 재전송은 일어나지 않기 때문에, '신뢰성이 없는 패킷 교환 프로토콜'이라고 할 수 있습니다.
이더넷 레이어에서 데이터 패킷이 이더넷 프레임(Ethernet frame)이라는 구체적인 이름이 있듯이, IP 프로토콜에서 패킷은 이따금 IP Datagram으로 불리기도 합니다. 이더넷 프레임과 마찬가지로 IP Datagram은 엄격히 구조화 돼 있습니다. 이 중 가장 중요한 부분은 Header와 Payload입니다.
이더넷 프레임 안에는 데이터 페이로드 섹션이 존재하며, 이것이 바로 IP Datagram입니다. IP Datagram의 모든 데이터는 이더텟 프레임 안에 캡슐화 됩니다.
IP Datagram 또한 Payload를 가지고 있으며, 이 paylaod의 내용물은 TCP 또는 UDP 패킷입니다. 여기서 우리가 네트워크 레이어를 왜 학습해야 하는지 알 수 있습니다. 각 레이어는 바로 위 상위층에서 필요하게 됩니다.
IP 주소는 네트워크부와 호스트부로 나눌수 있습니다. 앞서 IBM의 IP 주소에 관해 언급했었는데, IP 주소가 9.100.100.100 이라면 네트워크부는 첫 옥텟이고 호스트부는 그 나머지 입니다.
트랜스포트층의 주요 역할은 애플리케이션 프로그램 간 통신을 구현하는 것입니다. 컴퓨터 내부에서는 동시에 여러 프로그램이 작동합니다. 어떤 프로그램과 다른 어떤 프로그램이 통신하는지 식별할 수 있어야 하며, 이를 위해 "포트 번호"라는 식별자를 사용합니다.
TCP는 신뢰성이 있는 트랜스포트층 프로토콜입니다. 호스트 간 데이터가 무사히 도착하는 것을 보증하며, 도중 데이터를 옮기고 패킷이 없어지거나 순서가 바뀌어도 TCP가 해결해줍니다. 이 외에도 여러 기능을 가지고 있습니다. 하지만, 커넥션의 확립 및 끊기를 위해 패킷을 7번이나 주고 받기 때문에 쓸데없는 데이터가 늘어날 수 있습니다. 그리고 효율성 향상을 위한 복잡한 장치를 가지고 있어 음성, 영상과 같이 일정 간격으로 데이터를 전송하는 통신에는 적합하지 않습니다.
UDP는 TCP와 달리 커넥션리스형이고 신뢰성이 없는 트랜스포트층 프로토콜입니다. UDP는 송신한 데이터가 상대에게 도달했는지, 아닌지를 확인하지 않습니다. 이 작업이 필요한 경우 애플리케이션 프로그램이 수행하도록 합니다. UDP는 패킷 수가 적은 통신이나, 브로드캐스트, 비디오, 음성 등 멀티미디어 통신에 적합합니다.
여러 종류의 케이블과 네트워크 장치가 컴퓨터끼리 서로 통신을 하기 위해 사용됩니다. 컴퓨터 네트워크는 오늘날 매우 중요한 부분이기 때문에, 우선 케이블의 종류와 네트워크 장치에 대해 구분할 수 있도록 배워봅시다.
케이블은 컴퓨터 간 데이터를 주고 받을 수 있도록 해 줍니다. 오늘날 네트워크 케이블이라고 하면 크게 copper와 fiber로 나눌 수 있습니다.
Copper는 절연제 안에 여러 구리선이 감긴 형태로 되어 있으며, 가장 일반적인 네트워킹 케이블입니다. 컴퓨터가 바이너리 데이터로 통신을 할 때 이 구리선을 통해 전압(voltage)를 교환하여 이루어집니다. 수신처 시스템은 이 voltage를 0과 1로 변경할 수 있고 이는 곧 다른 형식의 데이터로 변경됩니다. 일반적으로 사용되는 형태로는 Cat5, Cat5e, Cat6가 있으며, 카테고리5 또는 6의 약자입니다. 카테고리 별로 다른 물리적 특성을 가집니다. 예로, 구리선 뭉치의 비틀림 수에 따라 사용 길이와 전송 속도가 달라집니다. Cat5는 오래된 형태이며, Cat5e와 Cat6가 이를 대부분 대체했습니다.
카테고리 별 케이블 종류를 육안으로 구분하기는 어렵습니다. 중요한 점은, 구리선들의 비틀림 정도가 데이터 전송 속도와 외부 영향에 대한 저항력에 매우 크게 영향을 미친다는 것입니다. Cat5는 crosstalk 때문에 Cat5e로 대부분 대체되었습니다. crosstalk는 한 전선이 인접한 전선에 전자기적 혼선 효과를 일으키는 것으로, 수신처에서 데이터를 이해할 수 없게 만들어 네트워크 에러를 발생시킵니다.
고위층의 프로토콜은 분실된 데이터를 감지하고 데이터 재전송을 요청하는 수단이 있습니다. 물론 이러한 동작은 더 많은 시간이 들게 합니다. Cat5e는 데이터 재전송이 필요한 경우를 감소시켜 주기 때문에, 평균적으로 데이터를 전송하는데 걸리는 시간을 파악하는데 수월합니다. Cat6는 좀 더 엄격한 스펙을 가지고 있어 crosstalk를 감소시킵니다. 하지만, 엄격한 스펙으로 고속망에서는 전달 가능한 최대 거리가 더 짧습니다.
Fiber는 fiber optical cable(광섬유 케이블)의 축약형으로, 내부에 머리카락 굵기의 얇은 유리 튜브로 구성되어 있습니다. 이 튜브는 빛줄기를 운반합니다. Copper가 데이터를 0과 1로 전압을 사용해 전달하는 것과는 다르게, Fiber는 빛의 파동을 이용합니다. Fiber는 전자 방해가 많은 환경에서 사용되기도 하는데, 이는 Copper를 사용시 이러한 환경에서 전달하는 데이터가 영향을 받을 수 있기 때문입니다. Fiber는 Copper보다 일반적으로 데이터 전송 송도가 더 빠르고 데이터 분실 없이 더 멀리 전달 가능하지만 더 비싸고 약합니다.
케이블은 지점 간 네트워크 연결을 할 수 있게 해 줍니다. 히지만, 세계의 수많은 컴퓨터를 연결하기에 효율적이지 못합니다. 허브는 많은 컴퓨터와 네트워크 연결을 가능하게 해 주는 장치입니다. 허브에 접속한 컴퓨터는 동시에 다른 모든 컴퓨터와 통신이 가능합니다. 전달 받은 데이터를 무시할지 활용할지는 허브에 접속한 각 시스템이 판단해야 합니다. 이와 같은 방식은 네트워크 상에서 많은 노이즈를 발생시키는데, 이것은 collision domain이라고 합니다. collision domain이란 한번에 한 디바이스만 통신할 수 있는 것을 말하며, 이로 인해 여러 시스템이 동시에 통신을 시도하면, 속도가 매우 느려지게 됩니다. 이는 허브가 많이 사용되지 않는 이유이기도 합니다. 여러 컴퓨터를 연결하는데 사용하는 일반적인 디바이스는 스위치입니다. 허브는 layer 1의 물리적 디바이스 이지만 스위치는 데이터 링크 디바이스입니다. 즉, 이더넷 프로토콜의 데이터를 어디로 보내는지 알고, 해당 시스템에만 전달을 합니다.
Hub와 Switch는 로컬 네트워크와 같이 하나의 네트워크에 연결된 여러 컴퓨터를 연결하기 위해 주로 사용됩니다. 다른 컴퓨터와 네트워크 통신을 위해서는 주로 Router를 사용합니다. 라우터는 여러 독립적인 네트워크에 데이터를 전송을 할 수 있습니다. Hub는 물리층에, Switch는 데이터링크층에, 라우터는 네트워크층에서 운영됩니다. 스위치가 이더넷 데이터를 어느곳으로 보내야 하는지 결정합니다. 마찬가지로, 라우터는 전 세계의 여러 네트워크 중 어디로 보낼지에 대한 내부 테이블을 가지고 있고, 이를 이용해 IP 데이터를 어디로 보낼지 결정합니다.
우리가 가장 흔하게 접할수 있는 라우터는 집에서 사용하는 라우터입니다. 홈 라우터는 세세한 라우팅 테이블을 가지고 있지는 않습니다. 홈 라우터는 가정이나 사무실에서 발생한 트래픽을 ISP까지 전달하는 역할을 합니다. 트래픽이 ISP에 전달되면, 이곳에서 고수준의 코어 라우터가 전세계로 데이터를 송수신 할 수 있도록 조율합니다. 코어 라우터는 BGP(Border Gateway Protocol)을 통해 서로간 데이터를 공유하는데, 이를 통해 트래픽을 최적의 경로로 보내는 방벙을 알 수 있습니다.
일반적으로 네트워크에 연결된 하나의 디바이스 단위를 노드라고 부릅니다. 그리고 서버라고 하면 요청을 한 노드에 데이터를 제공하는 노드라고 생각할 수 있어요. 우리는 단순히 특정 디바이스를 서버 또는 클라이언트로 단정할 수만은 없습니다. 대부분의 경우 서버, 클라이언트 둘 다 될 수 있기 때문입니다. 예로 이메일 서버의 경우에도 DNS 서버와의 관계에서는 클라이언트가 됩니다.
linux 환경에서 아래의 명령어를 입력해 봅니다.
ping -c3 8.8.8.8
'8.8.8.8'은 구글의 특정 서비스 주소이며, ping은 해당 주소로 트래픽을 보내고 받을 수 있는지 테스트하는 명령어입니다. -c3는 3번의 테스트 메세지를 전송하고 결과를 프린트하는 명령어입니다.
$ ping -c3 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=63 time=62.4 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=63 time=83.4 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=63 time=79.0 ms
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2006ms
rtt min/avg/max/mdev = 62.429/74.952/83.420/9.042 ms
인터넷의 모든 트래픽은 패킷이라 불리는 메세지로 쪼개집니다. 패킷은 한 컴퓨터에서 다른 컴퓨터로 보내는 짧은 메세지입니다. 패킷을 우편엽서로 간주한다면, 네트워크 트래픽은 여러 엽서를 와이파이, 이더넷, 케이블 모뎀 등을 통해 컴퓨터 간 주고 받는 것으로 생각할 수 있습니다.
ping을 보내서 "3 packets transmitted, 3 received, 0% packet loss"와 같은 결과를 프린트했습니다. 이를 통해, 자신의 컴퓨터가 인터넷에 접속해 해당 ip로 트래픽을 보낼 수 있으며, 주소 8.8.8.8의 컴퓨터가 작동하고 있음을 알 수 있습니다.
Echo request라 불리는 메세지는 받는 쪽 컴퓨터의 operating system에 전달됩니다. HTTP나 SSH와 같은 네트워크 프로토콜은 이에 대한 응답을 하는 서버 프로그램이 있습니다. 하지만, ping의 경우 서버가 존재하지 않습니다. Echo request는 받는쪽 컴퓨터의 operating system에 도달하고 이곳에서 응답을 받습니다. 인터넷을 지원하는 모든 운영 시스템은 ping 또한 지원합니다.
Ping은 Http보다 단순하지만 그렇다고 Http가 ping 기반으로 되어 있지는 않습니다. 그렇다면 Http는 무엇에 기반하는지 알아보겠습니다.
linux machine에서 아래의 명령어를 입력해 봅니다.
printf 'HEAD / HTTP/1.1\r\nHost: en.wikipedia.org\r\n\r\n' | nc en.wikipedia.org 80
위키피디아 서버로부터 아래와 같이 Http 헤더를 확인할 수 있습니다.
HTTP/1.1 301 TLS Redirect
Date: Sun, 29 Dec 2019 04:05:25 GMT
Server: Varnish
X-Varnish: 335024246
X-Cache: cp5010 int
X-Cache-Status: int-front
Server-Timing: cache;desc="int-front"
Set-Cookie: WMF-Last-Access=29-Dec-2019;Path=/;HttpOnly;secure;Expires=Thu, 30 Jan 2020 00:00:00 GMT
Set-Cookie: WMF-Last-Access-Global=29-Dec-2019;Path=/;Domain=.wikipedia.org;HttpOnly;secure;Expires=Thu, 30 Jan 2020 00:00:00 GMT
X-Client-IP: 110.70.54.244
Location: https://en.wikipedia.org/
Content-Length: 0
Connection: keep-alive
printf는 자료를 형식화 하여 화면에 출력합니다. "|"는 UNIX 방식으로 한 명령어의 출력을 다른 명령어의 입력으로 연결할 수 있습니다. 여기서는 nc(netcat)의 input으로 전달되며, netcat은 네트워크를 통해 데이터를 읽거나 쓸(write) 수 있는 네트워크 유틸리티 입니다.
위에서 netcat과 printf를 이용해 http 응답을 받은 것이 의미하는 것은 printf는 네트워크에 대해 전혀 알지 못 한다는 점입니다. 또한 netcat은 http request의 형식에 대해 알지 못하며, 단지 특정 port에 접속해 string을 전달하는 역할을 합니다. 즉, 텍스트를 담당하는 layer와 port에 접속해 데이터를 주고 받는 두 개의 layer로 구분했습니다. 일반적으로 Http layer는 웹브라우저나 서버와 같은 프로그램에 의해 구동됩니다. 반면, lower layer에서 TCP는 operating system에 의해 구동됩니다.
네트워크 프로토콜에서 여러 layer가 존재합니다. IETF를 예로 들면 아래와 같은 layer가 있습니다. Applicatioin 프로토콜은 TCP, UDP와 같은 Transport layer에 기반합니다. 그리고 Transport는 Internet layer에, IP 프로토콜은 다양한 종류의 하드웨어에서 작동합니다. 각 층은 해당 층 밑의 layer에 기반하며, 상위 층에는 특정한 보증을 제공합니다.
웹 개발자이면 여러분은 아마도 서버를 직접 만들어 본 적이 있을 것입니다. 그렇다면 서버란 무엇이고, 프로그램이 서버가 되기 위해서 어떻게 해야 할까요? 서버란 클라이언트로부터 받은 요청을 처리할 수 있어야 합니다.
man nc를 입력하면 앞서 사용해 보았던 nc manual에서 client/server에 대해 참고할 수 있습니다. 터미털 창을 두 개 열어 nc 명령어를 이용해 한 쪽에서 port를 열고, 다른 한쪽에서 해당 포트로 접속하면 아래와 같이 서로 통신이 가능합니다.
위 통신을 Http가 관여하지는 않았습니다. 웹 서버가 아니고 한 층 밑의 TCP 서버입니다.
위 통신을 확장해 데이터 전송 모델을 만들 수 있습니다. 한쪽에서 "nc -l 1234 > filename.out" 명령어로 포트를 열고 다른 한 쪽에서 "nc host.example.com 1234 < filename.in" 명령어를 입력하면 파일을 전송하고, 전송이 완료되면 접속이 종료됩니다.
때떄로 UI 말고 직접 서버에 요청을 보내 서버에서 어떤 데이터를 전송하는지 직접 확인해 보고 싶은 경우가 생길 수 있습니다. 특정 웹사이트의 홈페이지 데이터를 받아보고 싶으면 아래와 같이 입력해 볼 수 있습니다. 이에 대한 응답에 Header도 함께 포함되서 받습니다.
printf "GET / HTTP/1.0\r\n\r\n" | nc google.com 8080
아래와 같이 명령어를 입력하면 전달 받은 정보를 파일로 저장할 수 있습니다.
printf "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n" | nc www.example.com 80 > example.txt
서버가 요구하는 요청 포맷을 알고 있으면 다른 종류의 통신을 할 수 있고, 아래의 예와 같이 SMTP 서버에 이메일을 발송 요청을 할 수도 있습니다.
$ nc [-C] localhost 25 << EOF
HELO host.example.com
MAIL FROM:<user@host.example.com>
RCPT TO:<user2@host.example.com>
DATA
Body of email.
.
QUIT
EOF
그렇다면 서버가 통신을 하는 Port 중 가장 큰 Port와 가장 작은 Port는 얼마일까요? port 1023까지는 열 수 없고, 열 수 있는 가장 큰 Port는 65535입니다.
$ nc -l 100
nc: Permission denied
$ nc -l 1023
nc: Permission denied
여기서 이상하게 생각되는 점이 있습니다. 우리는 SSH 웹 서버가 20이나 80의 Port에 응답하는 것을 확인할 수 있습니다. 그러면 nc는 낮은 수의 Port를 사용할 수 없는 이유는 무엇일까요? 대부분의 시스템에서 0부터 1023까지의 Port는 superuser account 또는 Unix의 root에 의해 예약된 Port입니다. 따라서, 만약 웹 서버를 Port 80에서 실행하고자 한다면 root로 실행하던가 또는 sudo 명령어를 함께 입력해야 합니다.
일반적으로 한 개의 프로그램만 주어진 포트에 응답을 합니다. 하지만, 일단 서버가 동작하면 Threads 또는 자식 프로세스를 실행해 포트로 접속해 오는 요청을 다룰수 있습니다. 또는 loop을 돌며 여러 요청을 일괄 처리할 수도 있습니다. netcat의 웹 서버가 아니며 오직 한 개의 접속만 처리를 합니다. Linux에서 "sudo lsof -i" 명령어를 입력하면 열린 파일과 네트워크 소켓 리스트를 볼 수 있습니다.
앞서 웹 서버에 Http request를 보내고 Http response를 받아 봤습니다. netcat으로 포트를 열고 브라우저로 해당 포트에 접속하면 브라우저에서는 아무일이 일어나지 않지만 nc에서는 아래와 같이 로그가 남습니다. 하지만, 브라우저에는 아무런 응답을 받지 못 하니, 아무 동작을 하지 않습니다.
브라우저에 Http로 응답을 보내고 싶으면, printf와 netcat을 이용해 아래와 같이 명령어를 입력해 리다이렉트로 브라우저의 Location을 변경할 수 있습니다.
printf 'HTTP/1.1 302 Moved\r\nLocation: https://play.watcha.net' | nc -l 2345
지금까지 netcat을 이용한 매우 간단한 네트워크 프로그램 모델에 대해 확인해 보았습니다. 하지만, 실제 웹 브라우저와 서버의 네트워크는 이보다 더 복잡합니다. 브라우저와 서버는 하나의 요청만 처리하지도 않으며, 요청을 순차적으로 처리하지도 않습니다. 브라우저가 서버로부터 페이지를 로드할 때를 예를 들면, html, 이미지 파일, 스크립트 등 여러 데이터를 가져옴니다.
프로그램이 여러 요청을 처리하는 방법은 다양합니다. SSHD와 같은 프로그램이 아직 사용하며 기본적인 방법 중 하나는 어떠한 요청이 들어오면 OS에게 자신을 둘로 쪼개 request를 처리할 수 있도록 요청합니다. 최근의 많은 서버가 사용하는 방식은 프로세스 또는 Thread의 pool을 만들고 각각 하나의 요청을 처리하도록 하게 하는 것입니다. 이것은 프로세스를 새로 시작하는 것보다 빠릅니다. 하지만, 한번에 얼마나 많은 connection을 처리할지에 대한 제한이 있습니다. 마지막으로 하나의 프로세스가 있고 이것이 요청을 번갈아 가며 처리하는 방식입니다.
여러분은 아마도 50.116.54.191나 8.8.8.8.와 같은 IP 주소를 본 적이 있을 것입니다. IP 주소는 인터넷상에서 특정 목적지를 나타내기 위해 사용됩니다. Web request, email, ping 등 인터넷상에서 움직이는 모든 메시지는 packet으로 쪼개져 이동합니다. 그리고 모든 packet은 발신처, 수신처에 대한 IP 주소를 포함하고 있습니다. 웹 페이지나 전자메일을 사용해 통신하기 위해서는 애플리케이션에서 사용하는 주소로부터 그에 상응하는 IP 주소를 알아야 합니다. 이더넷 등의 경우에는 MAC 주소를 사용해 패킷을 전달합니다. 이렇게 실제 통신은 IP만으로 실현되는 것이 아니라 IP를 지지하는 각종 관련 기술에 의해 실현됩니다.
일반적으로 사용자가 브라우저에서 웹사이트에 접속할 때 ip 주소 대신 "www.watcha.com"과 같은 형식의 hostname을 이용한 웹 주소를 입력합니다. 그 이유는 IP 주소를 일일이 사람이 기억하는 것은 어렵기 때문입니다. 호스트명이 ip 주소로 전환되기 위해서는 Domain Name System(DNS)을 거쳐야 합니다. DNS는 네트워크 인포메이션에 관한 디렉토리입니다. 가장 널리 알려진 종류는 A-Record이며 "www.watcha.com"와 같은 이름을 IPv4 주소로 변경해 줍니다. 브라우저와 같은 클라이언트 프로그램은 이 record를 검색해 웹사이트의 주소를 찾습니다.
인터넷의 기원이라 할 수 있는 ARPANET에서는 호스트 파일을 네트워크 인포메이션 센터에서 직접 관리했습니다. 그리고 다른 컴퓨터는 정기적으로 센터로부터 데이터베이스를 다운받아 사용했습니다. 하지만, 네트워크의 규모가 커지며 이러한 방식으로 한 장소에서 집중 관리하는 것이 불가능해졌습니다. 이를 효율적으로 관리하기 위해 DNS가 개발되었습니다. DNS에서는 사용자가 호스트명을 입력하면 자동으로 데이터베이스 서버를 검색해 IP 주소 정보를 얻을 수 있습니다.
웹사이트 운영자로서 유저가 자신의 웹사이트에 접근할 수 있도록 하려면, 여러분은 DNS에 등록을 해야합니다. 도메인을 등록해 이 도메인이 자신의 IP를 가리키도록 해야 합니다. 때문에 DNS는 매우 중요합니다. 구글과 마이크로소프트도 DNS 도메인 접근이 단절된 적이 있습니다. DNS는 SSL, 쿠키 보안을 위시한 HTTP 보안 메카니즘의 한 부분입니다.
초기에는 호스트명만으로 IP 주소를 관리했기 때문에 같은 호스트명을 사용할 수 없었습니다. 하지만 피리어드로 연결한 구조의 계층적인 도메인명을 사용함으로써 좀 더 자유롭게 호스트명을 붙일 수 있게 되었습니다.
Name server란 해당 네임 서버가 설치된 계층의 도메인명을 관리하는 호스트와 소프트웨어를 말합니다. 네임 서버도 계층별로 설치되어 있는데, 이 중 루트 네임 서버는 DNS의 데이터 검색에서 가장 중요한 역할을 합니다. 관리하고 있는 도메인보다 아래 계층인 경우는 호스트명이나 서브 도메인을 자유롭게 설정할 수 있습니다. 하지만, 해당 계층의 도메인명이나 IP 주소를 설정하는 경우 상위 계층의 네임 서버에 설정 추가 또는 변경 요청을 해야 합니다. DNS에 의한 IP 주소 검색은 루트 네임 서버부터 순서대로 이루어집니다. 때문에, 모든 네임 서버는 루트 네임 서버의 IP 주소를 등록해야 합니다. 루트 네임 서버의 최신 IP 주소 정보는 아래 웹 사이트에서 얻을 수 있습니다.
http://www.internic.net/zones/named.root
DNS에 조회를 하는 호스트나 소프트웨어를 resolver라 합니다. resolver라 불리는 DNS 클라이언트 코드는 모든 Operating System에 포함되어 있습니다. 앞서 살펴보았던 NC, ping, 웹브라우저와 같은 프로그램들은 resolver를 이용할 수 있습니다. DNS 테스트를 위해 다음에서 shell utility인 host와 dig를 사용하도록 하겠습니다.
참고로, linux에서 host 명령어를 통해 DNS 검색을 할 수 있습니다. man 명령어를 통해 메뉴얼을 볼 수 있으니 한 번 읽어보면 여러 옵션들에 대해 살펴볼 수 있습니다.
Dig 명령어를 이용하면 Host 명령어와 같은 정보를 제공하지만, 좀 더 기술적이고 세부적인 양식으로 정보를 확인할 수 있습니다. Host가 사람이 읽기 쉬운 방식으로 정보를 제공한다면, Dig는 DNS 서버의 구성파일과 가까운 양식으로 정보가 제공됩니다. 도메인에 대한 IP정보, DNS 레코드 타입 뿐만 아니라 어떠한 서버가 응답을 주었는가와 메타데이터 등 추가적인 정보도 확인할 수 있습니다.
DNS record type에 대해 간단히 살펴보면 아래와 같습니다.
클라이언트의 resolver는 보통 가장 가까운 caching DNS 서버에 요청을 합니다. 그것은 local home router일 수 있으며, ISP나 Google public DNS 서비스 일 수 있습니다. caching 서버가 요청 받은 내용을 모를 경우, 다른 nameserver로 query를 전달합니다. 그리고 응답을 받으면 그 값을 cache에 저장합니다. 도메인이 변경된 경우 cache된 정보가 이전의 도메인을 기억하고 있을 수 있습니다. 떄문에, DNS 서버는 "Time To Live"라는 cache를 얼마나 간직하고 있을지에 대한 정보가 있으며, 이 시간이 만료되면 cache 서버는 authoritative 서버로부터 다시 정보를 불러옵니다.
도메인은 쿠기 보안이나 SSL 등 몇몇 HTTP 기능 중 중요한 부분을 차지합니다. 하나의 웹 서버는 다른 도메인 이름을 가진 여러 웹사이트의 요청을 처리할 수 있습니다. 때문에 HTTP 요청에 host header가 존재하는 이유입니다. 요청을 보낼 때 웹 서버에 어떤 도메인에 요청을 보내는 것인지 알리기 위해서입니다. host header는 HTTP 요청의 필수적인 한 부분입니다.
웹앱이 쿠키를 설정할 때 도메인 이름을 기준으로 설정합니다. SSL 보안 인증 또한 도메인 이름을 기준으로 발행됩니다. SSL은 몇몇 보안적인 목적으로 사용하는데, 브라우저 서버간의 통신을 암호화하거나 데이터가 통신 도중 읽히는 것을 방지합니다. 또한, 브라우저가 데이터를 요청한 사이트가 자신이 요청한 올바른 사이트인지 검증을 하도록 돕습니다.
DNS 도메인은 트리구조로 구성되어 있습니다. 예로, .com 이라는 top-level 도메인이 있고 그 밑에 subdomain으로 google.com이 있습니다. 그리고, 이러한 top-level 도메인을 관리하는 서버가 별도로 존재합니다.
초창기에는 www.stanford.edu와 같이 웹서버가 도메인 앞에 www을 포함하는 것이 일반적이였습니다. 최근에는 무수히 많은 도메인이 웹 트랙픽에 사용되며, 많은 기관들이 도메인에서 www를 생략하고 있습니다. 예로, www.github.com은 C-Name이며, github.com이라는 A-record의 별칭입니다. www를 붙일지 말지에 대한 결정은 거의 브랜딩적인 관점에서 차이가 오며 기술적인 차이는 매우 작습니다.
앞서 언급한 글에서의 IP Address는 IP version 4 address입니다. 오늘날 인턴넷 프로토콜에서 사용하는 주요 두 버전은 v4와 v6입니다. v4이 더 오래된 버전이며 대부분의 인터넷 트래픽이 v4를 사용하고 있습니다. 두 가지 버전을 모두 사용하고 있지만 두 버전의 외관은 매우 다르게 생겼습니다. IPv4는 점으로 4등분 된 숫자로 구성됩니다. 각 숫자는 1 byte(or octet) 또는 8 bits 입니다. 따라서, 수학적으로 숫자 0 ~ 255로 표현할 수 있습니다. 그러면 왜 255일까요?
컴퓨터는 숫자를 2진수로 표현하며, 컴퓨터 메모리는 0과 1 bit로 나열됩니다. 하지만, 우리가 python과 javascript와 같은 언어로 코드를 작성할 때 이러한 binary를 직접 볼 일은 없습니다. 숫자는 10진수로 표현되며 string과 boolean과 같은 값으로 실제 binary를 프로그래머가 접할 필요가 없도로 합니다. 알파벳 a를 이진수로 나타내면 01100001이지만, 이 글자를 프린트 하기 위해 이진수를 알 필요는 없습니다.
하지만 IP 주소의 경우는 다릅니다. 네트워크를 통해 전송되는 모든 정보는 연속된 bit의 형태로 이동합니다. 이것은 packet이라는 형태로 나뉘고 각 packet은 sender와 recipient의 IP 주소를 가지고 있으며, IP 주소는 binary로 돼 있습니다.
IP 주소는 32 bit 또는 4 바이트입니다. 몇몇 구형 컴퓨터에서 다른 사이즈의 바이트를 사용하기 때문에 4 octets이라고도 부릅니다. octet은 8 비트입니다. 아래의 binary와 hexadecimal은 같은 IP 주소를 나타냅니다.
네트워킹에서 field의 길이로 bit의 값을 말합니다. 예로, IPv4 주소의 경우 32 bit로 표현합니다.
네트워크 상의 각 IP 주소는 다른 주소와 구분이 되어야 합니다. 주어진 특정 bit로 구성할 수 있는 고유의 값은 한정되어 있습니다. 예로, 1 bit로는 2개의 구분값을 만들 수 있고, 2 bit로는 4개, 3 bit로는 8개를 만들 수 있습니다. 만약 3 bit에서 작동하는 네트워크가 있다면, 이 네트워크는 8대의 머신만 가질 수 있습니다.
앞서 가장 큰 포트 넘버는 65535라고 했습니다. 이보다 더 큰 포트 넘버를 사용할 수 없는 이유 packet header의 포트 넘버를 위한 공간이 16 bits 넓이로 돼 있기 때문입니다.
32비트 수로 4등분된 IPv4 주소의 각 부분은 octet 또는 8 비트를 나타냅니다. 이는, 읽기 편하게 하기위한 일종의 convention이며, 실제 컴퓨터간 통신할 때에는 네트워크상 다른 데이터와 마찬가지로 binary로 표기됩니다. 하지만, 32비트로 가능한 모든 수가 실제 주소로 사용되지는 않습니다. 몇몇은 특별한 프로토콜을 위해 사용되고, 또 몇몇은 테스팅이나 프라이빗 네트워크를 위해 사용됩니다. 뒤이어 살펴보겠지만, 32비트로 가능한 모든 숫자를 다 사용한다고 해도 필요한 공용 IP를 주소를 담는데는 한계가 있습니다.
아래의 사진은 IPv4 주소에 대한 공간을 시각화 한 것입니다. 각 네모는 주소의 첫 octet이 가질수 있는 수를 의미합니다. 예로, 오른쪽 끝의 15는 첫 octet이 15로 시작하는 모든 IPv4 주소를 나타냅니다.
IPv4 주소 중 8분의 1은 공용 호스트를 위해 사용되지 않고 있습니다. 그리고, 만약 우리가 모든 가능한 수의 IPv4 주소를 사용한다고 해도 모든 호스트를 나타내기에는 부족합니다.
아마도 학교나 회사, 집 등에서 같은 네트워크에 있는 컴퓨터가 비슷한 IP 주소를 가지고 있는것을 본 적이 있을 것입니다. 좀 더 구체적으로 말하면 한 네트워크 블락의 주소는 앞의 일부가 같으며, 라우터를 거치지 않고 통신이 가능합니다.
하지만 모든 네트워크 주소가 같은 사이즈는 아닙니다. 특정 네트워크에 대해 이야기 할 때 우리는 그 주소의 특정 prefix 뿐만 아니라 길이에 대해서도 인지해야 합니다. 특정 주소의 prefix가 길면 특정 호스트를 구분할 수 있는 경우의 수가 적어지고, 반대로 짧으면 더 많은 호스트에 대한 주소를 할당할 수 있기에 더 큰 네트워크라고 말 할 수 있습니다.
예로, 24비트의 prefix를 가진 주소는 호스트를 위해 나머지 8비트를 사용할 수 있습니다. 이를 보통 convention으로 "/24"라고 표기합니다. (ex, 120.51.100.0/24) 만약 네트워크 prefix가 22비트와 같이 더 짧은 경우는 호스트를 위해 10비트가 주어지고 "/22"로 표기합니다.
그럼 위 주소는 얼마나 많은 호스트를 유지할 수 있을까요? 10비트의 경우2의 10승이며 1024입니다. 최상단과 하단의 주소는 예약돼 있고 첫 주소는 보통 라우터입니다. 따라서, 1021 호스트를 유지할 수 있습니다.
서버의 네트워크상 잘못된 설정은 예기치 못한 문제를 야기할 수 있기 때문에, 위와 같은 사항을 인지하는 것은 중요합니다. 만약 한 컴퓨터는 다른 컴퓨터와 직접 통신을 하고 상대방 컴퓨터는 라우터를 통해 통신한다면 매우 이상한 문제를 발생시킬 수 있습니다. 따라서, 서버 네트워크를 설정하는데 위와 같은 이해가 필요합니다.
Subnet Mask는 네트워크 사이즈를 표기하는 또다른 방법입니다. Subnet Mask는 binary로 돼 있으며 왼편에는 1로 오른편에는 0으로 표기된 수로 구성됩니다.
다음의 /24 주소는 binary로 표기하면, 24개의 1과 8개의 0으로 표기됩니다. 1로만 구성된 octet은 255이고, 0로만 구성된 octet은 0이기에 subnet mask로 표기 시 255.255.255.0이 됩니다. 때때로 subnet mask를 hexadecimal로 표기하는 시스템도 있습니다. 이러한 경우 subnet mask는 ff, ff, ff, 00이 됩니다.
Network prefix는 꼭 온전한 octet일 필요는 없으며, 네트워크는 여러 사이즈로 할당이 가능합니다. 원한다면 관리의 편이를 위해 net block을 chunk나 subnet으로 나눌수 있습니다.
예로, 171.64.0.0/14라는 스탠포드 대학의 주소가 있습니다. /14는 2 octet 보다 작으며, 이 네트워크 상 모든 주소는 첫 8비트가 같은 주소를 가질 것입니다. 즉 이 네트워크 상 모든 주소는 171로 시작하고 두번째 octet은 6비트만 고정되어 있습니다. 그리고, 두번째 octet의 나머지 2비트의 여유가 있습니다. 즉, 이 octet에서 4개의 다른 수를 가질 수 있습니다. 구체적으로, 모든 주소는 171.64, 171.65, 66, 67로 시작할 수 있습니다.
그렇다면 /14의 subnet mask는 십진수로 어떻게 표현하고, 얼마나 많은 주소를 가질 수 있을까요?
지금까지 네트워크에 관한 기본적인 여러 사항들을 알아봤습니다. 그러면 개발자로서 우리는 왜 이러한 것들을 알아야 할까요?
인터넷 상의 모든 트래픽은 패킷이라는 메세지로 나누어지며, 각 패킷은 발신, 수신에 대한 주소를 가지고 있습니다. Ping을 예로 들면, 연속된 패킷을 주고 받게 됩니다. 즉, 특정 서버 또는 호스트가 있다면, 통신을 위해 구분된 주소를 알아야 합니다.
우리는 앞서 IP 주소가 세상의 모든 컴퓨터 수를 수용하기에 부족하다는 것을 배웠습니다. 세상에는 약 40억 개의 IPv4 주소가 있으며, 세계 인구 수는 약 76억 입니다. 게다가, 큰 회사나 기관의 경우는 다수의 IP 주소를 사용하고 있습니다.
앞서 IP 주소를 특정 호스트에 종속된 것과 같은 느낌으로 글을 작성했습니다. 하지만, 엄밀히 말하면 호스트보다 인터페이스에 종속된다고 하는것이 좀 더 정확합니다. 랩탑의 경우에도 여러 네트워크 인터페이스를 가질 수 있으며, 각 인터페이스는 복수의 주소를 가질 수 있습니다.
예로, 이더넷 인터페이스, 와이파이 인터페이스가 있고 또 각 머신은 loopback이라는 자기 자신과 통신하는 인터페이스를 가지고 있습니다. 그리고 다른 파트의 네트워크와 통신을 위한 터널 인터페이스도 있고, Virtual Machine과 같은 가상 머신을 위해 호스트 오퍼레이팅 시스템과 게스트 오퍼레이팅 시스템을 연결해 주는 인터페이스도 있습니다.
리눅스의 경우 ip addr show
명령어를 통해 해당 머신이 어떠한 인터페이스를 가지고 있는지 확인할 수 있습니다. 제 맥북의 VM의 리눅스 환경에서 위 명령어를 입력해 아래와 같은 출력물을 얻었습니다.
위 출력물을 통해 제 가상화 머신은 loop back 인터페이스와 이더넷 인터페이스를 가지고 있고, IP 주소도 확인할 수 있습니다. lo
, eth0
라는 2개의 인터페이스를 확인할 수 있습니다. 하나는 loopback 인터페이스, 다른 하나는 이더넷 인터페이스 입니다. 맥북의 경우는 ifconfig | less
를 통해 확인할 수 있습니다.
Loopback 인터페이스에 관해 좀 더 살펴보면, 항상 127.0.0.1의 IP 주소를 가지면 호스트명은 localhost입니다. 이것은 프로그램이 네트워크 스택을 이용해 다른 프로그램과 통신할 수 있도록 해 줍니다.
라우터의 가장 단순한 예로 홈라우터를 들 수 있고, ISP나 데이터센터와 같은 곳은 큰 규모의 라우터를 가지고 있을 것입니다. 일반적으로, 라우터라고 하면 두 개의 다른 IP 네트워크를 연결해 주는 장치이며, gateway 역할을 합니다. 대게 대부분의 호스트는 IPv4 주소를 위해 한 개의 인터페이스를 가지고 있지만, 라우터의 경우 여러개를 가질 수 있습니다.
로컬 네트워크 상 호스트는 default gateway(라우터)를 알고 있고, 이 라우터는 인터넷과 연결이 돼 있습니다. 보통 같은 와이파이 또는 네트워크에 접속한 컴퓨터는 서로간 로컬인 상태이기에, 다른 네트워크를 거치지 않고 직접 패킷을 전달할 수 있습니다.
만약, 같은 네트워크 블락에 존재하지 않는 컴퓨터끼리 통신을 위해서는 라우터를 거쳐야 합니다. 하지만, 이 라우터도 나머지 인터넷 세상과 연결을 위해 default gateway를 가질 수 있으며, 이러한 과정을 거치면 default gateway를 가지지 않는 defaultless 단계에 이릅니다.
리눅스에서는 ip route show default
명령어로, 맥에서는 netstat -nr
명령어로 default gateway를 확인할 수 있습니다. 이 명령어를 이용해 defualt gateway IP 주소를 확인하고, ping을 보내 응답이 얼마나 빠른지 확인해 볼 수 있습니다.
ARP는 IP 주소로부터 물리적인 주소를 구하는 프로토콜입니다. IP Datagram이 형성되면 이더넷 프레임 안에 캡슐화 됩니다. 바꿔 말하면, 송신하는 디바이스는 이더넷 프레임 헤더 완성을 위해 MAC 주소를 알아야 합니다. 만약 특정 IP 주소로 데이터를 보내고 싶고, ARP 테이블에 데이터가 없는 경우를 가정해 보아요. ARP Table은 IP 주소와 MAC 주소를 매칭한 리스트입니다. 해당 node가 ARP 메세지를 EFHs(MAC 브로드캐스트 주소)로 보내면. 이 ARP 메세지는 로컬 네트워크 내 모든 컴퓨터에 전달됩니다. 해당 IP 주소의 디바이트가 이 메세지를 받으면 MAC 주소와 함께 ARP response를 보냅니다. 송신 디바이스는 이제 MAC 주소를 응답 받고 이더넷 프레임을 준비할 수 있습니다. 추가로, 한 번 취득한 MAC 주소는 수 분간 캐시됩니다. 그리고 ARP Response를 하는 쪽에서도 MAC 주소를 Cache 한다고 합니다.
ICMP는 IP 패킷의 배송 중 이상이 발생해 패킷을 전송할 수 없는 경우, 패킷의 송신처에 이상을 알려주기 위해 사용하는 프로토콜입니다. 네트워크 설정 후 작동이 잘 되는지, 또는 장애가 발생 했을 때 원인 파악하는 것이 중요한데 ICMP는 이러한 원인을 통지해 주는 기능이 있습니다.
ICMP의 패킷은 헤더와 데이터 섹션으로 간단한 구성으로 돼 있습니다. 첫 필드로는 "destination unreachable"이나 "time exceeded"와 같은 메세지 타입이 있습니다. 그 다음 코드 부분에는 메세지 타입 보다 좀 더 구체적으로 장애 원인을 규정하는 코드가 들어 있습니다. 또 그 다음에는 Checksum이 있습니다. Rest of the header는 optional로 추가 정보를 보낼 수 있는 부분입니다. 데이터 섹션은 오직 ICMP 수신자가 장애 원인에 대해 알 수 있도록 전체 IP 헤더와 장애가 난 패킷 payload의 첫 8 바이트가 실려 있습니다.
ICMP의 패킷은 헤더와 데이터 섹션으로 간단한 구성으로 돼 있습니다.
네트워크 상 호스트를 관리하는 것은 시간이 오래 걸리고 쉽지 않은 작업입니다. TCP/IP 네트워크 상 모든 컴퓨터는 IP 주소, Subnetmask, 게이트웨이, 네임서버 이렇게 최소 네 가지는 필요합니다. 이 네 가지 중 일반적으로 subnet mask, primary gateway, DNS 서버는 같을 것입니다. 하지만, IP 주소는 네트워크 상 각 노드마다 달라야 하기 때문에 까다로운 설정 작업이 필요합니다. 여기에서 DHCP가 등장하게 되었습니다.
DHCP는 네트워크 상 호스트 설정을 자동으로 해주는 애플리케이션 층 프로토콜 입니다. DHCP는 호스트 설정 작업의 부담을 감소시키고 또한 IP 주소 선택을 도와줍니다. 클라이언트의 경우 통신을 위해 어떠한 IP 주소를 가질지는 그리 중요하지 않습니다. 하지만, 올바른 네트워크로부터 IP를 부여 받는 것은 중요합니다.
DHCP 구성에는 몇가지 스탠다드가 있습니다. Dynamic Allocation 방식은 클라이언트를 위해 IP 주소 리스트를 별도고 보관하다, 디바이스 네트워크게 접속할 때 IP를 할당하는 방식입니다. 클라이언트가 네트워크에 접속할 때마다 IP 주소가 변경될 수 있습니다. Automatic Aollocation 방식은 Dynamic 방식과 비슷한데, 가장 큰 차이점은 DHCP 서버가 과거 클라이언트와 IP 주소의 매칭 이력을 기억하고 가능하면 동일한 IP 주소를 할당하는 방식입니다. 그리고 Fixed allocation이 있는데 직접 MAC 주소와 이와 상응하는 IP 주소 리스트를 추가해야 하는 방식입니다.
클라이언트가 네트워크 설정 정보를 얻고자 시도하는 과정을 DHCP Discovery라고 하며, 네 단계로 이루어 집니다.
이러한 설정 과정을 DHCP lease라고 부르며, 만료 시간이 존재합니다. 몇일일 수도 있고 수분일 수도 있습니다. 시간이 경과하면 클라이언트는 위의 과정을 다시 진행해야 합니다. 클라이언트측에서 접속을 해제할 때 직접 DHCP 서버에 IP 주소를 반납할 수도 있습니다.
앞서 살펴 보았듯이 수용 가능한 IPv4 주소가 세계 인수구 보다 부족한 것을 확인했으며, 또 많은 사람들이 하나 이상의 컴퓨터를 사용하고 있습니다. 이에 대한 해결책으로 하나의 가정, 사무실 또는 특정 단체에 하나의 주소만 할당하는 것입니다. 그리고 랩탑이나 스마트폰, 스마트 TV 등과 같은 장치는 이 한 개의 주소 뒤에 있습니다.
우리의 집에 있는 라우터는 default gateway와 같이 작동합니다. 라우터는 ISP에 접속해 하나의 공용 IP 주소를 받고, 내부의 컴퓨터, 랩탑, 스마트폰에 private IP 주소를 할당합니다. 가장 일반적인 홈 라우터의 private IP 주소는 192.168.0.0/24, default gateway는 192.168.0.1 입니다. 인터넷에서 검색을 해 본다면 RFC 1918 이라 불리는 인터넷 표준에 명시된 것을 확인할 수 있습니다. private IP 주소는 NAT (Network Address Translation)이라 불리는 시스템과 함께 사용됩니다.
private IP와 public IP가 트래픽이 오갈때, 라우터는 네트워크 주소를 새로 작성하거나 변환합니다. 라우터는 어떠한 private IP 주소 및 포트가 어떤 public 주소 및 포트와 연결되었는지 대한 데이터를 가지고 있습니다. 아마도 여러분의 집이나 사무실은 NAT를 사용하고 있을것입니다.
NAT는 로컬 네트워크에서 프라이빗 IP 주소를 사용해 인터넷에 연결할 떄 글로벌 IP 주소로 변환해 주는 기술이며, 기본적으로 고갈된 IPv4 주소를 위해 태어난 기술입니다.
하지만, NAT가 IP 주소 부족에 대한 본질적인 해결책은 아니며 또다른 문제점을 생성합니다. 그것은 엔드 유저가 다른 사람이 접속할 수 있는 서버를 운영할 수 없으며, 엔드 유저가 네트워크 애플리케이션을 만들거나 디버깅 하는 것을 어렵게 합니다.
Private 주소의 Private은 어떠한 보안이나 사적인 것을 의미하지 않으며, 오직 로컬 네트워크에서만 유효하다는 것을 나타냅니다. 공용 인터넷 상에서는 사용할 수 없습니다. 아마도 수많은 사람들이 다른 NAT 라우터 뒤에서 192.168로 시작하는 IP 주소를 사용할 것입니다.
만약 여러분의 컴퓨터가 private IP 주소를 사용하고 있다면, 다른 쪽에서 공용 IP를 사용하는 라우터나 그에 상응하는 것이 존재할 것입니다. 웹서버나 다른 인터넷 상 서비스는 여러분의 Private 주소를 알 수 없으며, 공용 IP만 확인이 가능합니다.
NAT는 IP 주소 부족에 대한 근본적이 해결책이 될 수 없습니다. 실직적인 해결책은 IPv6이며 현재는 점진적으로 사용이 확대되고 있습니다. v5는 실험적인 프로토콜 버전이었고 실패했기 때문에, v4에서 v6로 바로 넘어가고자 합니다.
IPv6는 긴 주소를 가짐으로써 기존의 문제를 해결했습니다. 128 비트 또는 16 octet과 같이 v4에 비해 네 배나 긴 주소를 가집니다. 엔드유저에 할당 가능한 가장 작은 주소 단위는 /64이며 이는 v4 전체 공간보다도 훨씬 큽니다.
바꿔말하면, 이는 IP 주소가 매우 길어진다는 것을 의미합니다.
포스트 앞 부분에서 netcat을 사용할 때 TCP를 살짝 보았습니다. TCP는 두 프로그램간 string으로 된 바이트를 전송할 수 있게 합니다. TCP는 네트워크 프로토콜의 한 층이며, 모든 종류의 인터넷 애플리케이션을 지원하는 프로토콜입니다. HTTP나 다른 애플리케이션은 이 TCP 위에서 만들어졌고, TCP는 IP(Internet Protocol) 위에서 만들어졌습니다.
프로토콜은 목적에 맞게 추상화된 층으로 나누어져 있습니다. 보통 각 층별 별도로 작업을 진행하지만, 해당 층에 영향을 미치는 하위층에 대해 아는 것 역시 중요합니다. 웹 애플리케이션이 리소스 요청을 하거나 응답을 받는데 HTTP에 의존합니다. HTTP 애플리케이션을 만들기 위해 Flask와 같은 라이브러리를 사용하기도 합니다.
HTTP 레이어에서 관찰할 수 있는 가시적인 개념으로는 URL, method, cookie, HTTP verb 등이 있습니다. 하위 레이어에서 오류나 이상 현상 발생 시 대부분 HTTP 층에서 관찰할 수 있습니다. HTTP는 브라우저나 웹서버 또는 프록시, 방화벽 등에서 구현되며, 해당 코드는 TCP를 이용합니다. 하지만, HTTP 요청을 보내기 위해 서버의 특정 포트에 연결해 바이트를 전송을 하는 코드는 웹 서버 일부에 해당합니다. 클라이언트 측 웹앱이 구현할 필요는 없으며, 브라우저와 서버가 구현해 놓은 기능을 이용하면 됩니다. 브라우저 자체에서 어떠한 데이터를 라우터에 전송할지 와이파이나 이더텟 어답터에 말하는 것은 아니고, 컴퓨터의 OS가 제공하는 TCP 네트워킹 서비스를 이용합니다.
OS가 제공하는 TCP 네트워킹 코드는 더 하위층인 IP 프로토콜에 의지해 호스트간 패킷을 전달합니다. IP는 물리적으로 같은 네트워크상의 기기에 데이터 전달을 위해 와아피이나 이더넷과 같은 하드웨어에 의지합니다.
모든 네트워크 애플리케이션이 TCP를 사용하지는 않습니다. Ping의 경우 ICMP를 사용하고 DNS는 네트워크 타임 프로토콜과 같은 대상에는 주로 UDP를 사용합니다.
이러한 모든것의 기반이 되는 프로토콜은 Operating System이 제공합니다. 추가로, 주의할 점은 와이파이 접속과 같은 것은 TCP와는 아무 관련이 없으며, 또한 TCP 세션은 쿠키로 로그인 유저를 구분하는 웹 유저 세션과는 관련이 없습니다.
tcpdump는 호스트, 네트워크 간 트래픽의 패킷 세부사항을 보여주는 툴 입니다. 이름은 tcpdump 이지만 어떠한 네트워크 트랙픽이든 볼 수 있습니다. 이 명령어를 이용해 아래와 같이 ping 요청 시 패킷을 확인해 볼 수 있습니다.
만약 자신의 컴퓨터가 보내는 DNS 요청을 확인해 보고 싶으면 DNS가 사용하는 포트명을 입력하면 확인할 수 있습니다. 아래는 tcpdump -n port 53
명령어를 이용해 yahoo.com으로 ping을 보냈을 때 확인한 결과물입니다.
Ping이나 DNS 외에 웹 서버와 통신할 때에도 tcpdump를 이용해 패킷을 확인해 볼 수 있습니다. 이를 통해 TCP가 어떻게 작동하는지에 대한 감을 익힐 수 있습니다. tcpdump와 netcat을 이용해 "example.net"에 요청을 보낼때의 패킷을 확인해 볼 수 있습니다.
위 레코드 출력물에서 흥미로운 점이 한가지 있습니다. 각 레코드의 끝에 length 필드가 있으며, 이것은 해당 패킷 데이터의 크기를 나타냅니다. 대부분의 레코드는 length가 0이며 일부만이 0이 아닙니다. 이것은 TCP에서 중요한 개념인데, 클라이언트와 서버가 실제 데이터를 교환하기 전에 교환을 위한 서로간의 사전 연결 작업을 합니다. 그리고 실제 데이터 교환이 이루어 진 후, 이 연결을 해제합니다.
위 통신에서 처음 전송된 데이터 length는 38입니다. 그리고, 이후에 328 length가 있습니다. 38 length는 우리가 netcat을 통해 HTTP 요청을 보낼 때 전달한 데이터의 길이입니다. length가 321인 기록이 도메인 "example.net"으로부터 받은 응답에 대한 건입니다.
아래 다이어그램은 시간에 따라 클라이언트와 서버가 통신 하는 모습을 나타낸 것입니다. 다이어그램은 특정 프로토콜 층의 동작을 나타냅니다. 만약, 클라이언트에서 서버에 GET 요청을 보내고 응답을 받으면 HTTP 층의 모습을 보여주는 것입니다. 하지만, 그 응답이 6 메가바이트의 파일이라고 한다면 단순히 다이어그램에 화살표 하나로 표기할 수 없을 것입니다. 이렇게 HTTP 층에서의 한 통신은 더 낮은 층에서의 많은 작업을 내포하고 있을 수 있습니다.
그럼 우선 TCP 연결이 성립될 때 어떠한 작업이 필요한지 확인해 보겠습니다. 먼저, 클라이언트와 서버 간 커넥션에 관한 동의가 있어야 합니다. 초기에 클라이언트는 서버의 IP 주소, 포트 넘버를 알고 서버는 클라이언트에 관한 어떠한 것도 모릅니다. 그래서, 클라이언트에서 서버에 자신의 IP 주소와 포트 넘버 등을 전달하며 서버와 접속을 원한다고 전달해야 합니다.
TCP는 여기에 부가적인 작업을 더합니다. 각 엔드포인트가 전달한 데이터를 추적하고 수신인 측이 데이터를 전달받았는지 확인합니다. 그리고, 하위 네트워크에서 데이터의 순서를 변경했다 하더라도, 애플리케이션이 순서대로 된 데이터를 볼 수 있도록 해줍니다. 이 작업은 패킷에 번호표를 매김으로써 이루어집니다.
각 엔드포인트는 특정 패킷을 받은 사실에 대한 통지를 합니다. 만약 패킷을 받지 못 했다면, 보내는 측에서 통지를 받지 못 했기 때문에 해당 패킷을 다시 전달합니다. 또한, sequence number는 임의의 수로 돼 있기 때문에 다른 커넥션과 혼동될 일이 거의 없습니다.
클라이언트에서 첫 패킷을 보낼 때 패킷에는 sequence number가 담겨 있습니다. 서버가 응답을 보낼 때는 다른 sequence number가 담겨있고, 여기에 클라이언트측에서 보낸 패킷에 대한 acknowledgement(ack)도 포함되어 있습니다. 그리고 이후 각 엔드포인트에서 전달하는 패킷에는 acknowledgement가 포함되어 있습니다. 이를 통해서 가장 큰 sequence number를 알 수 있을 뿐만 아니라, 데이터를 재전송 할 필요가 없음을 알 수 있습니다.
클라이언트 측에서 어떠한 요청이 담긴 패킷을 서버에 보내면, 서버는 이에 대한 응답을 보내기 전 acknowledgement를 전달합니다. 실제 통신에서 파일을 전송할 때, 이러한 과정이 매우 많이 진행됩니다.
네트워크 상에서 패킷 전달하는 것이 실패할 수 있습니다. 또한, 데이터의 특정 chunk를 받았다고 통지를 하기 위해서 해당 chunk를 참고할 레퍼런스가 있어야 합니다. 무엇보다, 패킷의 전달이 순차적으로 이루어지지 않을 수도 있습니다.
이를 위해 각 엔트포인트의 Operating System에서 전달 받은 데이터를 위한 별도의 메모리 공간을 마련합니다. 그리고 패킷의 sequence number를 이용해 순서에 맞게 데이터를 다시 정렬합니다.
tcpdump를 이용해 출력한 패킷을 다시 살펴보면 Flag 필드를 확인할 수 있으며, 각 패킷은 [S], [S.], [.], [P.], [F.] 등 다른 내용을 가지고 있습니다. 저수준 언어세어 flag는 boolean으로 저장되어 메모리 상 single bit를 차지합니다. flag bit가 1이면 flag가 설정된 것이고, 0이면 cleared(unset) 된 것입니다.
본래 TCP 패킷에는 6가지 flag가 있었습니다. 이후 두 가지가 추가되었지만 아래 6가지에 비해 중요도가 떨어집니다.
각 엔드포인트가 데이터 전송을 완료해도 FIN 패킷을 보낼 수 있습니다. FIN 패킷을 받으면 해당 엔드포인트는 다시 ACK를 발송합니다. HTTP 데이터의 경우 클라이언트에서 HTTP 요청이 완료되면 먼저 FIN을 보냅니다. 그리고 서버에서도 전송이 완료된 후 FIN을 보내고, 이를 받은 클라이언트는 ACK를 보냅니다.
참고로, tcpdump를 이용해 ping 또는 DNS를 살펴보면 flag를 확인할 수 없습니다. 이는 ping은 ICMP를 DNS는 UDP를 사용하기 때문입니다. 이 프로토콜은 TCP flag 또는 sequence number를 가지고 있지 않습니다.
위와 같이 TCP는 패킷 로스 또는 다른 문제에 대한 여러 대비책이 있습니다. 하지만, 패킷 로스가 없도록 네트워크를 더 안정적으로 만들수는 없을까요?
호스트 A에서 B로 데이터 전송을 예를 들어 보겠습니다. 두 호스트는 속도가 빠른 네트워크에 연결 돼 있지만, 이를 연결하는 네트워크는 이보다 100배 느린 네트워크라고 가정해 봅시다. A에서 1 기가의 데이터를 전송하면 A는 근처 라우터로 데이터를 약 8초에 전송할 수 있습니다. 하지만 접점에 있는 네트워크는 이보다 느리기 때문에 13분의 시간이 걸립니다. 만약 호스트 A가 이와 같이 데이터를 전송하면 접점 네트워크는 이 데이터를 버퍼 후 점진적으러 흘려보내야 할 것입니다. 그리도 그동안 이 네트워크를 사용할 수 없을 것입니다.
때문에, TCP는 이러한 방식으로 진행하지 않습니다. 데이터를 최대 한도로 전송하지 않고 천천히 보내며 상대편에서 ACK를 보내면 전송 속도를 증가시킵니다. 라우터는 접점 네트워크가 너무 바쁘면 패킷을 드랍시키며 최적의 속도로 보내도로 접점 네트워크와 호흡을 맞춥니다.
라우터가 모든 데이터를 대기시키면 결국은 타임아웃이 발생합니다. 이러한 방식을 TCP Congestion Control이라 하며 TCP의 가장 중요한 성능적 특징중 하나입니다.
열려있지 않은 포트로 nc를 이용해 OS가 해당 서버에 접속을 시도하며, tcpdump로 패킷을 확인하면 OS가 접속 시도를 하지만 성공하지 못 하고 트래픽이 모두 drop 되는 것을 확인할 수 있습니다. 여기서 인지해야 할 점은 시간이 지나면 패킷을 보내는 속도가 점점 느려지다가 멈춘다는 것입니다. 속도가 느려지는 이유는 패킷 드랍의 가장 일반적인 원인이 congestion이기 때문입니다. 그리고, Congestion인 상태에서는 패킷을 빨리 보내지 않는다고 앞서 확인한 바 있습니다. TCP는 서버로부터 응답이 너무 늦어지면 접속 시도를 멈추고 에러를 발생시킵니다.
현재는 컴퓨터뿐만 아니라 자동차나 카메라, 가전기구 등의 사물까지도 네트워크를 이용해 정보를 주고 받는 통신을 하고 있습니다. 이러한 통신을 실현시켜주는 환경을 '네트워크'라고 하며, TPC/IP 는 네트워크상에서 가장 많이 사용되고 있는 통신 수단(프로토콜)입니다. 이용자의 급증, 대량의 정보를 효율적으로 처리 하는 방법, 보안 등 여러 개선할 점이 있지만, 네트워크를 안전하게 구축하고, 유지 및 운영을 위해 TCP/IP를 이해하는 것이 필수입니다.
컴퓨터 통신이 막 시작되었을 때는 각 컴퓨터 제조업체는 독자적인 네트워크 제품을 만들었습니다. 하지만, 이용자 입장에서 이것은 매우 불편했기 때문에 서로 다른 제조업체의 컴퓨터끼리도 자유롭게 통신할 수 있는 환경이 필요하게 되었습니다. TCP/IP는 국제 표준은 아니지만 디팩토 스탠다드로 전세계에서 가장 많이 사용하는 통신 프로토콜입니다. 프토토콜이 표준화되어 모든 기기가 이에 따르면, 컴퓨터의 하드웨어나 OS의 차이에 상관없이 네트워크에 연결된 컴퓨터와 통신할 수 있습니다.
네트워트 상 한 노드가 다른 노드가 커뮤니케이션 하는 방식에 대해서는 앞서 조금 자세히 살펴봤습니다. 우리는 컴퓨터 간 데이터를 주고 받는 것 뿐만 아니라 컴퓨터 위에서 작동하는 프로그램 간에도 데이터를 주고 받는 것을 원할 것입니다. Transport 층은 특정 애플리케이션 간 트래픽을 주고 받도록 만들어 주고, Application 층은 애플리케이션이 서로 이해할 수 있는 방식으로 커뮤니테이션 할 수 있도록 만들어 줍니다. 이번에는 TCP Port와 소켓, TCP 헤더 등에 대해서 알아보도록 할게요.
Transport 층은 네트워크에서 여러 중요한 기능을 하고 있습니다. 예를 들면, 트래픽을 multiplexing, demultiplexing 하는 것과, 커넥션 유지, 에러 체크와 데이터 인증을 통한 데이터의 온전성 유지 등과 같은 기능이 있습니다. Multiplexing은 네트워크 상 노드는 트래픽을 여러 다른 서비스로 발송할 수 있음을 의미합니다. 유사하게 demultiplexing 은 한 노드에 목적한 트래픽을 적절할 서비스로 보내는 것을 말합니다. 이 외에 TCP/UDP, 핸드셰이크에 대해서도 살펴보아요.
웹 애플리케이션의 사용자 경험에 영향을 미치는 요소는 다양해요. 트래픽이 이동하는데 시간이 소요되고, 때로는 너무 시간이 오래 걸려 사용자 경험을 안 좋게 만들수도 있어요. 속도 뿐만 아니라, Middle Box, Firewall도 때론 문제가 될 수 있어요. 우리의 웹앱에 영향을 줄 수 있는 여러 요소들에 대해 살펴볼게요.
인터넷을 통해 라우터는 패킷을 목적지에 전달합니다. 한 컴퓨터에서 다른 곳으로 전달하는 행위를 hop이라고 해요. 자신의 컴퓨터와 다른 곳에 있는 서버와의 hop은 traceroute라는 툴을 이용해 확인할 수 있어요. 호스트명이나 IP주소를 전달하면 목적지에 도착할 때 까지의 모든 라우터의 IP 주소를 확인할 수 있습니다. 좀 더 세부적인 사항은 mtr 명령어를 통해서 확인할 수 있어요.
Ping을 이용하면 자신의 컴퓨터와 상대방 측 컴퓨터와의 round trip time 을 확인할 수 있어요. 우리의 컴퓨터는 패킷이 반대편에 도착하는데 얼마나 걸리는지 알 수 없습니다. 하지만 패킷을 보내고 응답을 받는데 얼마나 걸리는지 확인할 수 있습니다. Ping time이라고도 부르는데, 이것은 네트워크 간 근접성을 측정하는 중요 요소 중 하나에요.
Ping은 traceroute에 비해 단순합니다. 인터넷 프로토콜에서 패킷의 흔적을 추적하는 기능은 설계되지 않았습니다. 하지만, Van Jacobson이라는 엔지니어가 무한 루프를 방지하기 위한 기능을 적용해 이를 구현하는 방법을 찾아습니다.
모든 패킷은 "Time To Live"(TTL)라는 필드를 가지고 있습니다. 처음에는 큰 숫자로 설정이 되는데, 패킷이 라우터를 만날때마다 1씩 차감이 됩니다. 즉, 라우터 설정에 오류가 있어 패킷이 무한 루프에 빠지면 TTL은 0이 되고 이 패킷은 만료됩니다. 패키의 TTL의 수명이 다하면 마지막으로 해당 패킷을 받은 라우터는 패킷 발신처에 에러 메세지를 보내고, 해당 라우터의 주소도 함께 전달합니다. 그러면 이제 traceroute가 어떻게 작동하는지 감이 오시나요? 맞습니다. TTL을 1부터 시작하는 패킷을 보내고, 목적지에 도달할 때까지 패킷의 TTL을 1씩 증가시키며 각 라우터가 보내는 에러 메시지를 취합합니다.
아래 그림의 오른편에 데이터 센터와 서버가 있습니다. 내부 네트워크 속도는 10 Gbit/sec 이더넷으로 매우 빨라요. Data Center가 라우터를 통해 Internet에 연결되었고, 이 라우터 또한 1 Gbit/sec로 꽤 빠릅니다.
이 서버에는 상대적으로 느린 네트워크 환경의 여러 유저가 접속합니다. 여기서 데이터를 옮길 수 있는 네트워크 링크의 Capacity를 bandwidth라고 해요.
서버측의 DC 라우터와 인터넷을 연결하는 링크 측면에서 bandwidth에 대해 고려해 볼 수 있고, 또한 유저와 데이터센터 서버와의 관점에서 bandwidth를 생각해 볼 수도 있어요.
만약 유저의 홈 네트워크가 매우 느리다면, 서버 네트워크를 아무리 향상시켜도 유저가 체감할 수 있는 효과는 거의 없을 거에요. 당연한 듯 보이지만 특정 상황에 대한 요인을 좁히는 것이, 서버 관리에서는 매우 중요합니다.
느린 네트워크 환경의 유저가 동시에 많이 접속한다면, 이러한 트랙픽들이 모여 접점의 네트워크보다 커질 수 있습니다. 이것은 서버가 유저 네트워크보다 훨씬 빠른 이유 중 한가지 이기도 합니다. 이는 또 다른 중요한 사항을 나타내는데, 만약 일반적인 유저가 접속 시 얼마 만큼의 트래픽을 만들고 동시 접속자가 얼마나 되는지 파악할 수 있다면 접점의 네트워크가 어느정도까지 빨라야 하는지 알 수 있습니다.