공통/Web & Network

네트워크의 흐름 2단계

반응형

프로토콜 스택 내부의 흐름

1. 소켓을 작성한다.


프로토콜 스택의 내부 구성

프로토콜 스택의 내부는 역할이 다른 몇 부분으로 나뉘어 있다.

  1. 맨 위의 네트워크 애플리케이션은 브라우저, 웹 서버 등의 프로그램이 해당되며, 여기부터 아래로 향하여 데이터 송수신 등의 일을 의뢰합니다.
  2. 애플리케이션 아랫부분에는 Socket 라이브러리가 있으며, 그 안에는 리졸버가 내장되어 있습니다. (DNS 리졸버는 DNS 서버에 조회하는 동작을 실행하는 역할을 수행합니다)
  • 그 아래가 OS의 내부를 나타내며, 여기에 프로토콜 스택이 존재합니다.
  1. 프로토콜 스택의 윗부분에는 TCP 프로토콜을 사용하여 데이터 송수신을 담당하는 부분과, UDP 프로토콜을 사용해서 데이터 송수신을 담당하는 부분이 있으며, 이 둘이 애플리케이션에서 보낸 의뢰를 받아서 송수신 동작을 실행합니다.
  2. 그 아래에는 IP 프로토콜을 사용하여 패킷 송수신 동작을 제어하는 부분이 있습니다. 인터넷에서 데이터를 운반할 때는 데이터를 작게 나누어 패킷이라는 형태로 운반하는데, 이 패킷을 통신 상대까지 운반하는 것이 IP의 주 역할입니다.
  3. IP의 아래에는 LAN 드라이버가 있는데, LAN 어댑터의 하드웨어를 제어합니다.
  4. 그리고 그 아래에 있는 LAN 어댑터가 실제 송수신 동작, 즉 케이블에 대해 신호를 송수신하는 동작을 실행합니다.


소켓의 역할

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

  • 대표적인 정보는 통신 상대의 IP 주소, 포트 번호, 통신 진행 상태 등이 있습니다.

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

  • 예를 들어 데이터를 송신할 때는 소켓에 기록되어 있는 상대측의 IP 주소나 포트번호를 대상으로 데이터를 송신합니다.


Socket을 호출했을 때의 동작

브라우저가 socket이나 connect라는 Socket 라이브러리의 프로그램을 호출했을 때 프로토콜 스택의 내부가 어떻게 움직이는지에 대한 내용

  1. 소켓을 만드는 단계
    • 애플리케이션이 socket을 호출하여 소켓을 만들 것을 의뢰하면 프로토콜 스택은 의뢰에 따라 한 개의 소켓을 만듭니다.
    • 이때 프로토콜 스택은 소켓 한 개 분량의 메모리 영역을 확보합니다.
  2. 소켓이 만들어지면 소켓을 나타내는 디스크립터를 애플리케이션에 알려줍니다. (디스크립터는 소켓을 식별하는 역할)
  3. 디스크립터를 받은 애플리케이션은 프로토콜 스택에 데이터 송수신 동작을 의뢰할 때 디스크립터를 통지합니다.


2. 서버에 접속한다 (3-way-handshake 과정)


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

  1. 통신 상대와의 사이에 제어 정보를 주고받아 소켓에 필요한 정보를 기록하고 데이터 송수신이 가능한 상태로 만듭니다.
    • 소켓을 만든 직후는 아무것도 기록되어 있지 않아서, 통신 상대가 누구인지 모릅니다. 따라서 서버의 IP주소, 포트 번호를 프로토콜 스택에 알리는 동작이 필요합니다.
    • 서버 입장에서도 통신하려는 클라이언트가 서버측에서버 측에 클라이언트의 정보를 전달해줘야 합니다. 이처럼 클라이언트에서 서버 측에 통신 동작의 개시를 전달하는 것도 접속 동작의 역할 중 하나입니다.
  2. 맨 앞부분에 제어 정보를 기록한 TCP 헤더를 배치합니다.


접속 실제 동작 (SYN → SYN + ACK → ACK)

애플리케이션이 Socket 라이브러리의 connect를 호출하면, 서버측의 IP 주소와 포트번호가 프로토콜 스택의 TCP 담당 부분에 전달됩니다. 그러면 TCP 담당 부분은 IP 주소로 표시된 서버의 TCP 담당 부분과 제어 정보를 주고받습니다. 그리고 TCP 헤더의 송신처와 수신처의 포트번호로 접속하는 소켓을 지정합니다. (SYN 컨트롤 비트를 1로 설정해서)
이렇게 TCP 헤더를 만들면 이것을 IP 담당 부분에 송신하도록 의뢰합니다.

  • IP 담당 부분이 패킷 송신 동작을 실행하고 네트워크를 통해 패킷이 서버에 도착하면 서버측의 IP 담당 부분이 이것을 받아 TCP 담당 부분에 건네줍니다. 이후 TCP 담당 부분이 TCP 헤더를 조사하여 기록되어 있는 수신처 포트 번호에 해당하는 소켓을 찾아, 필요한 정보를 기록하고 응답을 돌려보냅니다. (ACK 컨트롤 비트를 1로 설정해서)

페킷이 클라이언트에 돌아오고 IP 부분을 경유해서 TCP 부분에 도착하면 TCP 헤더를 조사하여 서버 측의 접속 동작이 성공했는지 확인합니다. 그리고 서버의 응답 패킷이 도착한 것을 서버에 알리기 위해 ACK 비트를 1로 만든 TCP 헤더를 반송함으로 접속 동작이 완료됩니다.
이로써 소켓은 데이터 송수신할 수 있는 상태가 되었고, 커넥션이 연결되었습니다.

  • 커넥션은 데이터 송수신 동작을 계속하고 있는 동안, 즉 close를 호출하여 연결을 끊을 떄 까지 계속 존재합니다.


3. 데이터를 송수신한다.


프로토콜 스택에 HTTP 요청 메시지를 넘긴다.

connect에서 애플리케이션에 제어가 되돌아오면 데이터 송수신 동작에 들어갑니다.

  • 이 동작은 애플리케이션이 write를 호출하여 송신 데이터를 프로토콜 스택에 건네주는 것부터 시작됩니다.

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

  • 한 번의 송신 의뢰에서 건네주는 데이터의 길이는 애플리케이션에 따라 결정되는 상황에서 받은 데이터를 곧바로 보내면 작은 패킷을 많이 보내서 네트워크의 이용 효율이 저하되므로 어느 정도 데이터를 저장하고 송수신 동작을 수행합니다
  • 데이터의 크기를 판단하는 요소 중 하나는 먼저 MTU라는 매개변수를 바탕으로 판단합니다. MTU는 한 패킷으로 운반할 수 있는 최대 길이로, 이더넷에서는 보통 1500바이트가 됩니다.
  • 다른 판단 요소는 타이밍으로, 프로토콜 스택은 내부에 타이머가 있어서 일정 시간 이상 경과하면 패킷을 송신합니다.


데이터가 클 경우 분할해서 전송

이떄 데이터가 클 경우 분할해서 보냅니다.

  • 송신 버퍼에 저장된 데이터가 MSS(MTU에서 헤더 길이를 제외한)의 길이를 초과하면, 송신 버퍼에 들어있는 데이터를 맨 앞부터 차례대로 MSS의 크기에 맞게 분할하고, 분할한 조각을 한 개씩 패킷에 넣어 송신합니다.


ACK 번호를 사용해서 패킷이 도착했는지 확인

  • 시퀀스 번호와 ACK 번호로 패킷이 수신 측에 도착한 것을 확인합니다.


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

윈도우 제어는 한 개의 패킷을 보낸 후 ACK 번호를 기다리지 않고, 차례대로 연속해서 복수의 패킷을 보내는 방법으로, ACK 번호가 돌아올 때까지의 시간이 낭비되지 않습니다.

  • 이때 수신측의 능력을 초과해서 패킷을 보내는 문제가 발생할 수 있는데, 수신 측에서 송신 측에 수신 가능한 데이터 양을 통지하고(TCP 헤더의 윈도우 필드), 송신 측에서는 이 양을 초과하지 않도록 송신 동작을 실행하는데, 이것이 윈도우 제어 방식의 개념.


HTTP 응답 메시지를 수신.

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

  • 그러면 프로토콜 스택에서는 데이터를 일시 보관하는 수신 버퍼를 사용해서 데이터를 수신합니다.
  • 그리고 수신 버퍼에서 수신 데이터를 추출하여 애플리케이션에 건네줍니다.


4. 소켓을 말소.


데이터 보내기를 완료했을 때 연결을 끊는다. (FIN → ACK → FIN → ACK)

애플리케이션이 송신해야 하는 데이터를 전부 송신 완료했다고 판단하면, 송신을 완료한 측이 연결 끊기 단계로 들어가는데, 서버측의 애플리케이션이 먼저 Socket 라이브러리의 close를 호출합니다 (클라이언트가 먼저 할 수도 있음)

  • 서버 측의 프로토콜 스택이 TCP 헤더를 만들고, 연결 끊기를 나타내는 정보를 설정합니다. (FIN 비트를 1로 설정)

서버에서 FIN 비트가 1로 설정된 TCP 헤더가 도착하면 클라이언트 측의 프로토콜 스택은 자신의 소켓에 서버 측이 연결 끊기 동작에 들어갔다는 것을 기록하고, FIN을 1로 설정한 패킷을 받은 사실을 알리기 위해 ACK 번호를 서버 측에 반송하고, 애플리케이션이 데이터를 가지러 올 때까지 기다립니다.

  • 애플리케이션이 read를 호출하여 데이터를 가지고 가면, 서버에서 보낸 데이터를 전부 수신했다는 사실을 클라이언트의 브라우저에게 알리면 클라이언트도 종료합니다. 그래서 클라이언트측의 애플리케이션도 close를 호출하여 데이터 송수신 동작을 끝냅니다.
  • 그러면 클라이언트 측의 프로토콜 스택은 FIN 비트에 1을 설정한 TCP 헤더를 만들고 서버 측에 전송합니다.


소켓을 말소

서버와의 대화가 종료되면, 잠시 기다린 후 소켓을 말소합니다. (오동작을 막기 위해 잠시 대기)

반응형

'공통 > Web & Network' 카테고리의 다른 글

[CORS] CORS 정리  (4) 2021.11.22
네트워크의 흐름 1단계  (0) 2021.08.01