CS/네트워크

소켓을 이용한 데이터 송/수신 과정, TCP에서 오류 회복 조치가 필요 없는 이유, ACK와 윈도우 제어

JWonK 2023. 7. 22. 17:56
728x90
반응형

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

 

 

5. 소켓을 작성한다.


 

1. 프로토콜 스택의 내부 구성

프로토콜 스택 내부 구성

 

 

  • 프로토콜 스택 내부는 역할이 다른 부분들이 나뉘어져있다.
  • 상하 관계는 작업을 의뢰하는 쪽이 위쪽에 있고, 의뢰를 받아 실제로 작업하는 쪽이 아래에 존재한다.
  • 맨 윗 부분은 네트워크 애플리케이션이다. 브라우저, 메일, 웹 서버 등 프로그램에 해당한다.
    • 네트워크 애플리케이션부터 아래로 향하여 데이터 송·수신 등의 일을 의뢰한다.
    • 브라우저 뿐만 아니라 다른 애플리케이션도 네트워크를 송·수신하는 동작은 비슷하다.
  • 그 아래 부분은 Socket 라이브러리이다. 그 안에는 리졸버가 존재한다.
  • 그 아래는 OS 내부이며 여기에 프로토콜 스택이 존재한다.
    • 프로토콜 스택 윗부분은 TCP라는 프로토콜을 사용하여 데이터 송·수신 담당하는 부분과 UDP 프로토콜을 사용하여 데이터 송·수신 담당 부분과 이 둘이 애플리케이션에서 보낸 의뢰를 받아 송·수신 동작을 수행한다.

 

- 브라우저나 메일 등의 일반적인 애플리케이션이 데이터를 송·수신할 경우에는 TCP

- DNS 서버에 대한 조회 등에서 짧은 제어용 데이터를 송·수신할 경우에는 UDP

 

  • 그 아래에는 IP 프로토콜을 사용하여 패킷 송·수신 동작을 제어한다.
    • 인터넷에서 데이터를 운반할 때는 데이터를 작게 나누어 패킷 형태로 운반하는데, 이 패킷을 통신 상대까지 운반하는 것이 IP의 주역할
    • 그리고 IP 안에는 ICMP와 ARP라는 프로토콜이 포함
      • ICMP : 패킷을 운반할 때 발생하는 오류를 통지하거나 제어용 메시지를 통지할 때
      • ARP : IP 주소에 대응하는 이더넷의 MAC 주소를 조사할 때 사용
  • 그 아래 LAN 드라이버는 LAN 어댑터의 하드웨어를 제어
  • 그 아래 LAN 어댑터가 실제 송·수신 동작을 실행

 

 

 

 

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

  • 프로토콜 스택 내부에 제어 정보를 기록하는 메모리 영역을 가지고 있으며, 여기에 통신 동작을 제어하기 위한 제어 정보를 기록
  • ex) 통신 상대 IP 주소, 포트 번호, 동작 현행 상태
  • 프로토콜 스택은 이 제어 정보를 참조하면서 동작

 

 

 

 

3. Socket을 호출했을 때 동작

브라우저가 socket이나 connect라는 Socket 라이브러리의 프로그램 부품을 호출했을 때 프로토콜 스택 내부 동작을 살펴본다

 

 

메시지 송신 동작

 

위에서 설명한 것처럼 이 그림에서 브라우저는 TCP 프로토콜을 사용하여 데이터를 송·수신해 줄 것을 의뢰하므로 TCP 담당 부분을 살펴본다.

 

  • 1번 동작을 통해 소켓을 만든다. 이 때 프로토콜 스택이 최초로 하는 일은 소켓 한 개 분량의 메모리 영역을 확보한다.
  • 소켓 제어 정보를 기록하는 메모리 영역은 처음부터 존재하는 것이 아니므로 확보해두는 것이 먼저이다.
  • 소켓이 만들어지면 소켓을 나타내는 디스크립터를 애플리케이션에 알려준다.
  • 디스크립터는 프로토콜 스택 내부에 있는 다수의 소켓 중 어느 것을 가리키는지 나타내는 정보이다.
  • 디스크립터를 받은 애플리케이션은 이후 프로토콜 스택에 데이터 송·수신 동작을 의뢰할 때 디스크립터를 통지한다.

 

 

 

 

 

 

 

6. 서버에 접속한다.


 

1. 접속의 의미

 

  • 소켓을 만들면 애플리케이션은 connect를 호출한다.
  • 그러면 프로토콜 스택은 자기쪽의 소켓을 서버측 소켓에 접속한다.
  • socket을 호출하여 소켓을 만드는 동작만으로는 프로토콜 스택에 아무 것도 전달되지 않는다.

그러므로,

  1. 서버의 IP 주소나 포트 번호를 프로토콜 스택에 알리는 동작이 필요한데, 이것이 connect 동작의 한 가지 역할이다.
  2. 클라이언트 측에서 서버 측에 통신 동작의 개시를 전달하는 것도 접속 동작의 역할 중 하나이다.
  3. 데이터 송·수신 동작을 실행할 때는 송·수신하는 데이터를 일시적으로 지정하는 메모리 영역이 필요한데, 이 영역을 '버퍼 메모리'라고 부른다. 버퍼 메모리 확보도 접속 동작의 역할 중 하나이다.

 

→ 통신 상대와의 사이에 제어 정보를 주고받아 소켓에 필요한 정보를 기록하고 데이터 송·수신이 가능한 상태로 만드는 것과 버퍼 메모리를 확보하는 것이 connect 동작의 역할이라고 볼 수 있다.

 

 

 

 

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

 

클라이언트와 서버가 서로 연락을 절충하기 위해 주고받는 제어 정보를 패킷의 맨 앞 부분에 배치하는 것을 헤더라고 부른다.

헤더의 형태로 제어 정보를 주고 받는 것이라고 생각하면 된다.

 

소켓에 기록한 제어 정보는 상대측에서 확인 불가능하다. 왜냐하면 규칙에 따라 헤더에 제어 정보를 기록하여 대화하면, 그것으로 클라이언트와 서버가 서로 연락을 취하기 때문이다.

 

예를 들어 내부 구조가 다른 윈도우와 리눅스라는 OS는 프로토콜 스택을 만드는 방법이 다르므로 필요한 제어 정보도 다를 것이다. 하지만 양자가 문제 없이 통신할 수 있으며 컴퓨터와 휴대 전화로 통신할 때도 마찬가지이다.

 

[통신 동작에 이용하는 제어 정보는 다음 두 종류]

1) 헤더에 기입되는 정보

2) 소켓(프로토콜 스택 메모리 영역)에 기록되는 정보

 

 

 

 

3. 접속 동작의 실제

 

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

 

  • 여기에 서버측의 IP 주소와 포트 번호를 쓰면 명령이 프로토콜 스택의 TCP 담당 부분에 전달된다.
  • 그러면 TCP 담당 부분이 IP 주소로 표시된 상대, 즉 서버의 TCP 담당 부분과의 사이에 제어 정보를 주고 받는다. 다음과 같은 단계로 진행된다.
  • 먼저 데이터 송·수신 동작의 개시를 나타내는 제어 정보를 기록한 헤더를 생성한다.
  • 중요한 것은 송신처수신처포트 번호이다. 이를 통해 송신처가 되는 클라이언트 측의 소켓과 수신처가 되는 서버 측의 소켓을 지정할 수 있다.
  • 즉 접속해야 하는 소켓이 어느 것인지 확실히 하고 컨트롤 비트인 SYN이라는 비트를 1로 만든다.

 

접속 동작의 처음은 TCP 담당 부분에서 접속을 나타내는 제어 정보를 기록한 TCP 헤더를 만드는 것이다. 
그리고 TCP 헤더의 송신처와 수신처의 포트 번호로 접속하는 소켓을 지정한다.

 

이렇게 해서 TCP 헤더를 만들면 이것을 IP 담당 부분에 건네주어 송신하도록 의뢰한다.

  • 그러면 IP 담당 부분이 패킷 송신 동작을 실행하고 네트워크를 통해 패킷이 서버에 도착하면 서버 측의 IP 담당 부분이 이것을 받아 TCP 담당 부분에 전달한다.
  • 이후 서버 측의 TCP 담당 부분이 TCP 헤더를 조사하여 기록되어 있는 수신처 포트 번호에 해당하는 소켓을 찾아낸다.
  • 접속을 기다리는 상태에 있는 소켓 중에서 TCP 헤더의 수신처 포트 번호와 같은 번호인 소켓
  • 해당하는 소켓이 발견되면 여기에 필요한 정보를 기록하고 접속 동작이 진행중이라고 바뀌며 이 과정이 끝나면 서버의 TCP 담당 부분은 응답을 돌려보낸다

 

클라이언트도 마찬가지로 SYN 비트 등을 설정한 헤더를 만들고 ACK 컨트롤 비트도 조정한다.

  • 패킷이 도착한 것을 확인하면서 동작하는데 이를 위해 ACK 비트가 필요하다.
  • 서버가 응답을 돌려보낼 때 ACK 비트를 1로 만들었는데, 이것과 같이 패킷이 도착한 것을 서버에 알리기 위해 ACK 비트를 1로 만든 TCP 헤더를 반송한다. 

 

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

 

 

 

 

 

 

 

7. 데이터를 송·수신한다.


 

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

위 과정들로 connect가 되어 애플리케이션에 제어가 되돌아오면 데이터 송·수신 동작을 진행한다.

 

  • 프로토콜 스택은 받은 데이터를 곧바로 송신하는 것이 아니라 일단 내부에 있는 송신용 버퍼 메모리 영역에 저장하고, 애플리케이션이 다음 데이터를 건네주기를 기다린다.
  • 기다리는 이유는 효율적인 데이터 송·수신을 위해서 이며 한 패킷에 저장할 수 있는 데이터의 크기에 따라 달라진다.
    • MTU : 한 패킷으로 운반할 수 있는 디지털 데이터의 최대 길이로 헤더를 포함함
    • MSS : 헤더를 제외한 상태의 디지털 데이터의 최대 길이
  • 다른 것은 타이밍이다. 데이터의 길이가 너무 길어지는 경우 송신 속도가 길어질 수 있으므로 적당한 길이에 적당한 타이밍에 데이터를 송신해야 한다.

 

 

 

 

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

송신 버퍼에 저장된 데이터가 MSS의 길이를 초과하면 송신 버퍼 맨 앞 데이터부터 차례로 MSS 크기에 맞게 분할하고, 분할한 조각을 한 개씩 패킷에 넣어 송신한다.

 

 

 

 

3. ACK 번호를 사용하여 패킷 도착 여부를 확인한다

TCP 담당 부분은 데이터를 조각으로 분할할 때 조각이 통신 개시부터 따져서 몇 번째 바이트에 해당하는지 세어둔다.

그리고 데이터의 조각을 송신할 때 세어둔 값을 TCP 헤더에 기록하는데, 이를 시퀀스 번호라고 한다.

 

 

 

 

이렇게 하면 수신측에서 패킷이 누락되었는지 확인할 수 있다.

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

 

  • 시퀀스 번호가 일정하면 이를 탈취하는 보안 위협이 존재
  • 따라서 랜덤 값으로 생성, 그렇다면 수신 측은 이를 어떻게 알 수 있을까
  • 데이터 송·수신을 시작하기 전 SYN이라는 제어 비트로 초기값을 통지한다.

 

 

 

[ 접속 동작 ]

  • 접속 동작을 실행할 때 클라이언트에서 서버로 보내는 데이터의 시퀀스 번호의 초깃값을 클라이언트에서 산출하여 서버에 통지 [1번]
  • 그러면 서버에서 초기값으로부터 ACK 번호를 산출하여 클라이언트에 반송, 최초의 초기값 통지가 도중에서 사라질 수 있으므로 이것이 서버에 도착한 것을 알리기 위해 ACK 번호를 반송하는 것 [2번]
  • 이 때 서버에서 클라이언트에서도 서버와 마찬가지로 바은 시퀀스 번호의 초기값으로부터 ACK 번호를 산출하여 서버에 반송 [3번]
  • 양방향 통신이 가능하지만 웹의 경우 최초에 클라이언트에서 서버로 시퀀스 번호와 함께 전송 [4번]
  • 데이터를 수신한 서버에서 ACK 번호를 반송 [5번]
  • 반대는 [6, 7번]

 

접속 동작

 

[ TCP에서 오류 회복 조치 기법 필요 없는 이유 중요!]

  • TCP는 이 방법으로 상대가 데이터를 받은 것을 확인하는데, 확인할 때까지 송신한 패킷을 송신용 버퍼 메모리 영역에 보관한다.
  • 그리고 송신한 데이터에 대응하는 ACK 번호가 되돌아오지 않으면 패킷을 재전송한다.
  • 구조가 이렇기 때문에 다른 곳에서 오류를 회복 조치할 필요가 없다.
  • 하지만 아무리 다시 보내도 수신을 못하면 무한반복되므로 곤란하다.
  • 따라서 몇 번 보내도 회복 전망이 없다고 판단하면 오류를 통지하고 송신 동작을 중지한다.

 

 

 

 

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

동기 방싱으로 패킷을 하나 씩 전송하면 효율이 떨어진다.

 

윈도우 제어는 한 개의 패킷을 보낸 후 ACK 번호를 기다리지 않고 차례대로 연속해서 복수의 패킷을 보내는 방법이다.

 

윈도우 제어 방식

 

  • 이론상으로 완벽하지만 애플리케이션에 건네주는 속도보다 빠른 속도로 데이터가 도착하면 수신 버퍼에 데이터가 차곡차곡 쌓여 넘치는 문제가 발생 할 수 있음
  • 수신측에서 송신 측에 수신 가능한 데이터 양을 통지하고, 수신측은 이 양을 초과하지 않도록 송신 동작을 실행하도록 해야한다
  • 수신 가능한 데이터 양의 최대값을 윈도우 사이즈라고 하며 이를 관리하며 효율적으로 관리한다.

 

 

 

 

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

  • 송신 측에서 보낸 데이터가 수신 측에 도착하여 수신 동작이 정상적으로 완료되었을 때 ACK 번호 송신측에 통지
  • 잠시 후 데이터를 애플리케이션에 건네주었을 때 윈도우를 송신측에 동지하는 상태가 되며 데이터의 패킷을 수신할 때마다 ACK 번호 통지와 윈도우 통지의 패킷이 하나씩 따로 따로 보내져야한다.
  • 이는 효율성 저하로 이어짐
  • 수신측은 ACK 번호나 윈도우를 통지할 때 잠시 기다리고 다음 통지 동작이 일어나면 한 개의 패킷으로 묶어서 전송한다
  • 예를 들면 ACK 번호의 송신을 대조할 때 윈도우 통지가 일어나면 ACK 번호와 윈도우를 한 개의 패킷에 합승시켜서 통지하여 패킷의 수를 줄일 수 있다.
  • 연속적으로 ACK 번호 통지가 이어진다면 최후의 것만 통지하고 도중의 것은 생략 가능

 

 

 

 

6. HTTP 응답 메시지 수신

 

브라우저의 의뢰를 받아 프로토콜 스택이 HTTP 리퀘스트 메시지를 보내는 일련의 동작에 대한 설명은 이것이 끝이다

 

데이터를 수신할 때도 데이터를 송신할 때와 마찬가지로 데이터를 임시 보관하는 수신 버퍼를 사용하며 동작은 아래와 같다

  • 프로토콜 스택은 수신 버퍼에서 수신 데이터를 추출하여 애플리케이션에 건네준다
  • 이때 리퀘스트 메시지의 송신을 완료하고 나서 얼마 안 된 시점이라면 아직 응답 메시지가 돌아오지 않았을 것이다
  • 응답 메시지가 돌아올 때까지 시간이 걸리므로 수신 버퍼에 데이터가 들어가지 않는다
  • 이 상태에서 더 이상 작업을 진행할 수 없으므로 프로토콜 스택은 의뢰받은 작업 즉, 수신 버퍼에서 수신 데이터를 추출하여 애플리케이션에 건네주는 작업을 잠시 보류한다
  • 그리고 서버에서 응답 메시지의 패킷이 도착했을 때 그것을 수신하여 애플리케이션에 건네주는 작업을 재개한다

 

 

간단 정리,

  • 수신한 데이터 조각과 TCP 헤더의 내용을 조사하여 도중에 데이터가 누락되었는지 검사하고 문제가 없으면 ACK 번호 반송
  • 그리고 데이터 조각을 수신 버퍼에 일시 보관하고, 조각을 연결하여 데이터를 원래 모습으로 복원한 후 애플리케이션에 전달
  • 구체적으로는 수신 데이터를 애플리케이션이 지정한 메모리 영역에 옮겨 기록한 후 애플리케이션에 제어를 되돌려줌
  • 그리고 애플리케이션에 데이터를 건네주고 나서 타이밍을 가늠하여 윈도우를 송신측에 통지한다.
728x90
반응형