성공과 실패를 결정하는 1%의 네트워크 원리 정리 - 2장. TCP/IP의 데이터를 전기 신호로 만들어 보낸다.

크리링·2022년 9월 6일
0
post-thumbnail

2.1 소켓을 작성한다

2.1.1 프로토콜 스택의 내부 구성

이 장에서는 OS에 내장된 네트워크 제어용 소프트웨어(프로토콜 스택)와 네트워크용 하드웨어(LAN 어댑터)가 브라우저에서 받은 메시지를 서버에 송출하는 동작을 탐험합니다.

애플리케이션 -> OS -> 드라이버 소프트웨어 -> 하드웨어

  • 애플리케이션
    * 네트워크 애플리케이션(Socket 라이브러리)
    • 브라우저, 메일러, 웹 서버, 메일 서버 등의 프로그램이 해당
  • OS
    * 프로토콜 스택
    • TCP(일반적인 애플리케이션에서 데이터 송수신), UDP(DNS 서버 등 짧은 제제어용 데이터 송수신)
    • IP(패킷 운반, 경로 결정)
  • 드라이버 소프트웨어
    - LAN 드라이버
  • 하드웨어
    - LAN 어댑터



2.1.2 소켓의 실체는 통신 제어용 제어 정보

프로토콜 스택은 내부에 제어 정보를 기록하는 메모리 영역을 가지고 있으며, 여기에 통신 동작을 제어하기 위한 제어 정보를 기록합니다.

  • 프로토콜 스택에 제어 정보
    IP 주소
    포트 번호
    통신 동작의 상태

프로토콜 스택은 이 제어 정보를 참조하면서 동작합니다.



2.1.3 Socket을 호출했을 때의 동작

  1. socket을 호출하여 소켓을 만들 것을 의뢰하면 프로토콜 스택은 의뢰에 따라 한 개의 소켓을 만듭니다.
  2. 소켓을 나타내는 디스크립터를 애플리케이션에 알려줍니다.(프로토콜 스택의 내부에 있는 다수의 소켓 중 어느 것을 가르키는지를 나타냄).
  3. 디스크립터를 받은 애플리케이션은 이후 프로토콜 스택에 데이터 송수신 동작을 의뢰할 때 디스크립터를 통지




2.2 서버에 접속한다

2.2.1 접속의 의미

소켓을 만들면 애플리케이션(브라우저)는 connect를 호출합니다. 그러면 프로토콜 스택은 자기쪽의 소켓을 서버측 소켓에 접속합니다.

데이터를 신호로 변환하여 송신하기만 하면 언제든지 통신이 가능

소켓을 만든 직후는 아무것도 기록되어 있지 않으므로 통신 상대가 누군지 모릅니다.(저장 공간만 할당) 서버의 IP주소나 포트 번호를 프로토콜 스택에 알리는 동작이 필요

접속 동작 첫번째는 통신 상대와의 사이에 제어 정보를 주고받아 소켓에 필요한 정보(IP 주소, 포트 번호)를 기록하고 데이터 송수신이 가능한 상태로 만드는 것

데이터 송수신 동작을 실행할 때 일시적으로 저장하는 메모리 영역 버퍼 메모리 버퍼 메모리 확보 -> 접속



2.2.2 맨 앞부분에 제어 정보를 기록한 헤더를 배치한다

제어 정보는 크게 헤더, 소켓(프로토콜 스택의 메모리 영역)에 기록되는 정보

제어 정보를 패킷의 맨 앞부분에 배치하는 곳 -> 헤더

클라이언트와 서버는 헤더를 통해 정보를 기록하여 연락을 취하면서 동작 진행

  • ex) 송신측 : 데이터 송신 동작 개시합니다.
  • 수신측 : 예 알겠습니다.
  • 송신측 : ㅇㅇ번째 데이터 보냅니다.
  • 수신측 : ㅇㅇ번째 데이터 받았습니다.
  • ...

이 대화가 가능하지 않으면 통신이 성립되지 않습니다.

제어 정보는 소켓에 기록하여 프로토콜 스택의 동작을 제어하기 위한 정보가 더 있습니다.(애플리케이션에서 통지된 정보, 통신 상대로부터 받은 정보 등이 수시로 기록 but, 소켓에 기록하는 제어 정보는 프로토콜 스택에 만드는 사람(ex. 윈도우와 리눅스)에 따라 달라지므로 간단히 설명 불가)



2.2.3 접속 동작의 실제

connect(디스크립터, 서버측의 IP 주소와 포트 번호);

서버측의 IP 주소와 포트 번호를 쓰면 명령이 프로토콜 스택의 TCP 담당 부분에 전달됩니다. 그러면 TCP 담당 부분은 IP 주소로 표시된 상대, 즉 서버의 TCP 담당 부분과의 사이에 제어 정보를 주고 받습니다.

헤더에는 다수의 항목이 있는데 중요한 것은 송신처수신처포트 번호입니다.

이를 통해 송신처가컨트롤 비트SYN이라는 비트를 1로 만듭니다.

이렇게 TCP 헤더를 만들면 이것을 IP 담당 부분에 건네주어 송신하도록 의뢰합니다. 그러면 IP 담당 부분이 패킷 송신 동작을 실행하고 네트워크를 통해 패킷이 서버에 도착하면 서버 측의 IP 담당 부분이 이것을 받아 TCP 담당 부분에 건네줍니다.서버 측의 TCP 담당 부분이 TCP 헤더를 조사하여 기록되어 있는 수신처 포트 번호에 해당하는 소켓을 찾아냅니다.

클라이언트와 마찬가지로 송신처와 수신처의 포트 번호나 SYN 비트 등을 설정한 TCP 헤더를 만듭니다. 그리고 응답을 돌려보낼 때 패킷을 받았다는 것을 알리기 위해 ACK라는 컨트롤 비트도 1로 만듭니다.

패킷이 도착한 것을 서버에 알리기 위해 ACK 1로 만들어 반송합니다.

이로써 소켓은 데이터를 송수신할 수 있는 상태가 됩니다.

  • 커넥션 : 소켓을 연결하는 파이프




2.3 데이터를 송수신한다

2.3.1 프로토콜 스택에 HTTP 리퀘스트 메시지를 넘긴다

connect에서 애플리케이션에 제어가 되돌아오면 데이터 송수신 동작에 들어갑니다. 이 동작은 애플리케이션이 write를 호출하여 송신 데이터를 프로토콜 스택에 건네주는 곳부터 시작됩니다.

프로토콜 스택은 받은 데이터를 곧바로 송신하는 것이 아니라 일단 자체의 내부에 있는 송신용 버퍼 메모리 영역에 저장하고, 애플리케이션이 다음 데이터를 건네주기를 기다립니다.

건네주는 데이터의 길이는 애플리케이션의 사정(ex. OS)에 따라 결정되며, 프로토콜 스택에서는 제어할 수 없습니다.

프로토콜 스택은 내부에 타이머가 있어서 이것으로 일정 시간 이상 경과하면 패킷을 송신합니다. (시간은 OS 종류나 버전에 따라 결정됩니다.)



2.3.2 데이터가 클 때는 분할하여 보낸다

HTTP 리퀘스트 메시지는 보통 그다지 길지 않으므로 한 개의 패킷에 들어가지만, 폼을 사용하여 긴 데이터를 보낼 경우 등 한 개의 패킷에 들어가지 않을 만큼 긴 것도 있습니다.

송신 버퍼에 저장된 데이터는 MSS의 길이를 초과하므로 다음 데이터를 기다릴 필요가 없습니다.



2.3.3 ACK 번호를 사용하여 패킷이 도착했는지 확인한다

TCP에는 송신한 패킷이 상대에게 올바르게 도착했는지 확인하고, 도착하지 않았으면 다시 송신하는 기능이 있으므로 패킷을 송신한 후에는 동작으로 넘어갑니다.

시퀀스 번호 : 데이터의 조각을 송신할 때 세어둔 값을 TCP 헤더에 기록한 값.
패킷 전체의 길이에서 헤더 길이를 빼면 데이터의 크기를 계산하여 산출

수신 확인 응답 : 수신 측은 그 이전에 수신한 데이터와 합쳐서 데이터를 몇 번째 바이트까지 수신한 것인지 계산하고, 그 값을 TCP 헤더의 ACK 번호에 기록하여 송신측에 알려줍니다.

  1. 시퀀스 번호 초기값 (클라이언트 to 서버)
  2. ACK 번호 + 시퀀스 번호 초기값 (서버 to 클라이언트)
  3. ACK 번호 (클라이언트 to 서버)
  4. 시퀀스 번호 + 데이터 (클라이언트 to 서버)
  5. ACK 번호 (서버 to 클라이언트)
  6. 시퀀스 번호 + 데이터 (서버 to 클라이언트)
  7. ACK 번호 (클라이언트 to 서버)



2.3.4 패킷 평균 왕복 시간으로 ACK 번호의 대기 시간을 조정한다

ACK 번호가 돌아오는 것을 기다리는 시간을 타임아웃 값이라고 합니다.



2.3.5 윈도우 제어 방식으로 효율적으로 ACK 번호를 관리한다

한 개의 패킷을 보낼 때마다 ACK 번호를 기다리는 방법은 단순하지만 시간 낭비입니다.

수신 측의 TCP는 패킷을 수신하면 일단 수신용 버퍼 메모리에 데이터를 일시 보관합니다. 수신 버퍼에 데이터가 차곡차곡 쌓여서 곧 넘쳐버리는데 이 것을 초과하지 않도록 송신 동작을 실행하는 방식을 윈도우 제어 방식이라고 합니다.

윈도우 사이즈 : 수신 가능한 데이터 양의 최대값



2.3.6 ACK 번호와 윈도우를 합승한다

송수신 동작의 효율성을 높이기 위해 ACK 번호와 윈도우를 통지하는 타이밍을 고려해야 합니다.

수신측에서 애플리케이션에 데이터를 건네주고 수신 버퍼의 빈 영역이 늘어났을 때 이것을 송신 측 에 통지하는 것을 윈도우 통지 타이밍이라고 합니다.

ACK 번호는 수신측에서 데이터를 받았을 때 내용을 조사하여 정상 수신을 확인할 수 있는 경우에만 송신측에 보냅니다. 데이터를 수신한 후 즉시 보낸다.



2.3.7 HTTP 응답 메시지를 수신한다

브라우저는 리퀘스트 메시지를 송신해 달라고 의뢰하고, 끝나면 서버에서 돌아오는 응답 메시지를 받기 위해 read 프로그램을 호출합니다.




2.4 서버에서 연결을 끊어 소켓을 말소한다

2.4.1 데이터 보내기를 완료했을 때 연결을 끊는다

데이터 송수신 동작이 끝난 후 프로토콜 스택의 움직임을 설명합니다.

웹이라면 브라우저에서 웹 서버에 리퀘스트 메시지를 보내고, 서버가 이것에 응답하여 응답 메시지를 반송 완료하면 데이터 보내기가 완료된 것입니다. 서버측이 연결 끊기 단계에 들어갑니다.

  1. 서버측의 애플리케이션이 먼저 Socket 라이브러리의 close를 호출합니다. 컨트롤 비트의 FIN 비트에 1을 설정하고, IP 담당 부분에 의뢰하여 클라이언트에 송신해달라고 합니다.
  2. 클라이언트 측은 서버에서 FIN에 1을 설정한 TCP 헤더가 도착하면 자신의 소켓에 서버측이 연결 끊기 동작에 들어갔다는 것을 기록합니다.
  3. FIN을 1로 설정한 패킷을 받은 사실을 알리기 위해 ACK 번호를 서버측에 반송하고 끝나면 애플리케이션이 데이터를 가지러 올 때까지 기다립니다.
  4. 잠시 후 애플리케이션이 read를 호출하여 데이터를 가지러 오고 나면 서버에서 보낸 데이터를 전부 수신 완료했다는 사실을 클라이언트 측의 애플리케이션(브라우저)에게 알립니다.
  5. 클라이언트 측의 애플리케이션도 close를 호출하여 데이터 송수신 동작을 끝냅니다.
  6. 그러면 클라이언트측의 프로토콜 스택은 서버측과 마찬가지로 FIN 비트에 1을 설정한 TCP 헤더를 만들고 IP 담당 부분에 의뢰하여 서버에 송신한 후 서버에서 ACK 번호가 돌아오면 서버와의 대화가 끝납니다.



2.4.2 소켓을 말소한다

서버와의 대화가 끝나면 소켓을 사용하여 서버와 대화할 수 없게 됩니다. 하지만 오동작이 있을 수 있으므로 바로 소켓을 말소하지 않고 잠시 기다린 후 소켓을 말소합니다.



2.4.3 데이터 송수신 동작 정리

TCP 프로토콜에서 애플리케이션의 데이터를 송수신하는 동작 정리

  1. 최초의 동작은 소켓을 작성하는 단계

    • 서버 측에서 애플리케이션이 동작하기 시작했을 때 소켓을 만들고 이것을 접속 대기상태로 만든다.
    • 클라이언트 측은 사용자가 무언가 조치를 취하여 서버에 액세스하는 동작이 시작될 때 일반적으로 패킷을 작성하지만, 이 단계에서는 아직 패킷을 주고받지는 않는다.
  2. 소켓을 만들면 클라이언트 서버를 향해 접속 동작을 실행

    • SYN을 1로 만든 TCP 헤더를 만들어 서버에 보냅니다.
    • 이 TCP 헤더에는 클라이언트가 서버에 데이터를 보낼 때 사용하는 시퀀스 번호의 초기값도 기록되어 있습니다.
    • 서버에서 클라이언트에 데이터를 송신할 때 이용하는 윈도우의 값, ACK 번호도 기록
    • 클라이언트에 도착하면 TCP 헤더를 받은 것을 나타내는 ACK 번호를 기록한 TCP헤더를 클라이언트가 서버에 보냅니다.
  3. 데이터 송수신 단계

    • 클라이언트에서 서버에 리퀘스트 메시지를 보내는 것부터 시작
    • TCP는 이것을 적당한 크기의 조각으로 분할하고 TCP 헤더를 맨 앞에 부가하여 서버에 보냅니다.
    • TCP 헤더에 송신 데이터가 몇 번째 바이트부터 시작되는지를 나타내는 시퀀스 번호가 기록
    • 서버에 도착하면 서버는 ACK 번호를 클라이언트에 반송
    • 클라이언트에서 서버에 리퀘스트 메시지를 보내면 서버가 응답 메시지를 반송
  4. 응답 메시지 보내기를 완료하면 데이터 송수신 동작이 끝나므로 연결 끊기 동작 시작

    • FIN을 1로 만든 TCP 헤더가 흐르고 이것을 받았음을 나타내는 ACK 번호의 TCP 헤더가 돌아온다.
    • 역방향으로 FIN 을 1로 만든 TCP 헤더와 ACK 번호의 TCP 헤더가 흐르다가 잠시 후 소켓이 말소




2.5 IP와 이더넷의 패킷 송수신 동작

2.5.1 패킷의 기본

TCP 담당 부분은 접속, 송수신, 연결 끊기의 각 단계에서 통신 상대와 대화할 때 IP 담당 부분에 의뢰하여 대화하는 데이터를 패킷의 모습으로 만들어 상대에게 도착합니다. 의뢰를 받은 IP 담당 부분이 어떻게 패킷을 상대에게 송신하는지 살펴보겠습니다.

TCP/IP의 패킷

MAC 헤더 IP 헤더 TCP 헤더 데이터 조각

  • 이더넷의 패킷 : MAC 헤더 + IP 헤더 + TCP 헤더 + 데이터 조각

  • IP의 패킷 : IP 헤더 + TCP 헤더 + 데이터 조각

    먼저 패킷의 송신처가 되는 기기가 패킷을 만드는데, 헤더에는 적절한 제어 정보를 기록하고, 데이터 부분에는 얼마간의 데이터를 넣은 후 패킷을 가장 가까운 중계 장치에 송신합니다.

    중계 장치는 도착한 패킷의 헤더를 조사하여 패킷의 목적지를 판단 합니다. 목적지를 향해 패킷을 송신하면 패킷은 다음 중계 장치에 도착

차례로 패킷을 중계하면 최종적으로 수신처의 기기에 패킷이 도착

송신처와 수신처의 기기 : 엔드 노드

순서

  1. IP가 목적지를 확인하여 다음 IP의 중계 장치(라우터)를 나타냅니다.
  2. 서브넷 안에 있는 이더넷이 중계 장치까지 패킷을 운반합니다.

MAC 헤더 : 이더넷용 헤더
IP용 헤더 : IP용 헤더



2.5.2 패킷 송수신 동작의 개요

IP 담당 부분은 다음 두 개의 헤더를 덧붙입니다.

  • MAC 헤더 : 이더넷용 헤더, MAC 주소를 씁니다.
  • IP 헤더 : IP용 헤더, IP 주소를 씁니다.



2.5.3 수신처 IP 주소를 기록한 IP 헤더를 만든다

IP 담당 부분은 TCP 담당 부분에서 패킷 송수신 의뢰를 받으면 IP 헤더를 만들어 TCP의 헤더의 앞에 붙입니다.

IP 헤더의 수신처 IP 주소에는 통신 상대의 주소를 설정합니다.
송신처 IP 주소는 송신처가 되는 LAN 어댑터를 판단하여 주소를 설정합니다.




2.6 UDP 프로토콜을 이용한 송수신 동작

2.6.1 수정 송신이 필요없는 데이터의 송신은 UDP가 효율적이다

어떤 상황에서는 TCP 보다 효율적으로 데이터를 다시 보낼 수 있습니다.



2.6.2 제어용 짧은 데이터

DNS 서버에 대한 조회 등 제어용으로 실행하는 정보 교환은 한 개의 패킷으로 끝나는 경우가 많으므로 UDP를 사용합니다.

UDP 헤더

  • 송신처 포트 번호 (16비트) : 이 패킷을 송신한 측의 포트 번호
  • 수신처 포트 번호 (16비트) : 이 패킷을 건네줄 상대의 포트 번호
  • 데이터 길이 (16비트) : UDP 헤더 이후의 길이
  • 체크섬 (16비트) : 오류 유무를 검사하기 위한 것



2.6.3 음성 및 동영상 데이터

음성이나 영상 데이터는 결정된 시간 안에 데이터를 건네주어야 합니다. 데이터의 도착이 지연되면 이것을 재생하는 타이밍이 맞지 않아서 음성이 끊기거나 영상이 멈춥니다. 몇 배나 더 빠른 고속 회선이 필요한데 UDP가 효율적입니다.

0개의 댓글