학교/네트워크

[네트워크] 2-1. TCP/IP의 데이터를 전기 신호로 만들어 보낸다.

daykim 2023. 3. 18. 15:28
 

성공과 실패를 결정하는 1%의 네트워크 원리 | Tsutomu Tone - 교보문고

성공과 실패를 결정하는 1%의 네트워크 원리 | 『성공과 실패를 결정하는 1%의 네트워크 원리』는 네트워크 전체의 움직임을 해설하고 현실의 네트워크 기기나 소프트웨어가 어떻게 움직이는지

product.kyobobook.co.kr

 

목차

  • 소켓을 작성한다.
  • 서버에 접속하다.
  • 데이터를 송,수신한다.

 

OS에 내장된 프로토콜 스택이 어떻게 송신을 의뢰하는지에 대해 설명한다.

 

소켓을 작성한다.


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

네트워크 애플리케이션
  • 웹 브라우저, 메일러, 웹 서버, 메일 서버 등의 프로그램
  • 여기부터 아래로 향하여 데이터 송, 수신등의 일을 의뢰한다.
  • 브라우저 분 아니라 어떤 애플리케이션도 네트워크에서 데이터를 송, 수신하는 동작은 거의 비슷하다.
  • Socket 라이브러리 : 리졸버가 내장됨
OS
  • 프로토콜 스택이 내장되어 있다.
  • 애플리케이션에서 보낸 의뢰를 받아 데이터 송, 수신 담당
    • TCP
      : 브라우저나 메일 등의 일반적인 애플리케이션이 데이터를 송, 수신할 경우 사용
    • UDP
      : DNS 서버에 대한 조회 등에서 짧은 제어용 데이터를 송, 수신할 경우 사용
  • IP
    • 패킷 송, 수신 동작을 제어한다.
    • 패킷을 통신 상대까지 운반하는 역할이다.
    • 패킷 : 인터넷에서 데이터를 운반하기 위해, 데이터를 작게 나눈 것
    • ICMP : 패킷을 운반할 때 발생하는 오류 통지, 제어용 메시지 통지할 때 사용
    • ARP : IP 주소에 대응하는 이더넷의 MAC 주소를 조사할 때 사용
LAN 드라이버 LAN 어댑터의 하드웨어를 제어한다.
LAN 어댑터 실제 송, 수신 동작, 즉 케이블에 대해 신호를 송, 수신하는 동작을 실행한다.

 

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

프로토콜 스택은 내부에 제어 정보를 기록하는 메모리 영역을 가지고 있다.
여기에 통신 동작을 제어하기 위해 아래와 같은 제어 정보를 기록한다.

  • IP 주소
  • 포트 번호
  • 통신 동작이 어떤 진행 상태인가

이러한 제어 정보를 기록한 메모리 영역이 소켓이라고 생각해라.

소켓의 역할

프로토콜 스택이 소켓에 기록된 제어 정보를 참조하여 다음에 무엇을 할지 판단할 수 있도록 하는 것이다.

ex) 윈도우의 'netstat' 명령어로 소켓의 내용을 화면에 표시 (p.106)

  • Proto : 프로토콜 종류
  • Local Address : netstat 명령을 실행한 기계 자체의 IP주소와 포트 번호
  • Foreign Address : 통신 상대측의 IP 주소와 포트 번호
  • State : 통신 상태 (LISTENING : 접속 대기 / ESTABLISHED : 접속 동작 끝나고 데이터가 통신중인지 나타냄)
  • PID : 소켓을 사용하고 있는 프로그램의 PID

 

3. Socket을 호출했을 때의 동작

TCP 담당 부분에 대한 설명이다.

1. 준비

<디스크립터> = socket(<IPv4 사용>, <TCP 사용>, ... );
  • 소켓을 만드는 단계
  • socket을 호출해 소켓을 만들 것을 의뢰하면, 프로토콜 스택은 의뢰에 따라 한 개의 소켓을 만든다.
  • 이 때 프로토콜 스택은 소켓 한 개의 메모리 영역을 확보하고, 초기 상태라는 것을 이 영역에 기록한다.
  • 소켓이 만들어지면, 디스크립터를 애플리케이션에 알려준다.
  • 애플리케이션은 프로토콜 스택에 데이터 송, 수신 동작을 의뢰할 때 디스크립터를 통지한다.
  • 디스크립터가 어느 소켓인지 나타내면, 프로토콜 스택쪽에서 필요한 정보를 알 수 있다.
  • 이를 통해 필요한 정보를 일일이 애플리케이션에서 통지받을 필요가 없어진다.

 

서버에 접속하다.


1. 접속의 의미

2. 접속

통신 상대와의 사이에 제어 정보를 주고받아 소켓에 필요한 정보를 기록하고, 데이터 송, 수신이 가능한 상태로 만드는 것이다.

애플리케이션 측

  • 소켓을 만들면 애플리케이션은 connect()를 호출해, 프로토콜 스택은 자기쪽 소켓을 서버측 소켓에 접속한다.
  • 이더넷이나 통신 회선은 항상 케이블에 연결되어 있으므로 언제나 신호를 보낼 수 있다.
  • 그러나 소켓을 만든 직후엔 아직 아무것도 기록되어 있지 않으므로 통신 상대가 누군지 모른다.
  • 그러므로 서버의 IP 주소나 포트 번호를 프로토콜 스택에 알리는 동작이 필요한데, 이것이 접속의 한 가지 역할이다.

서버측

  • 서버측 프로토콜 스택도 마찬가지로 소켓을 만든다.
  • 그러나 소켓 만드는것 만으론 통신 상대를 알 수 없다.
  • 그래서 클라이언트 측에서 '이곳의 IP 주소는 xxx.~이고, 포트 번호는 yyyy입니다. 데이터 송수신을 하고 싶은데 어떤가?' 라고 정보를 알려 통신하려는 클라이언트가 있다는 것을 서버측에 전달한다.
  • 따라서 서버측의 프로토콜 스택도 클라이언트의 정보를 갖는다.
  • 클라이언트 측에서 서버측에 통신 동작의 개시를 전달하는 것도 접속 동작의 역할 중 하나다.

 

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

앞에서 나온 '제어 정보'는 크게 두가지가 있다.

1. 헤더에 기입되는 정보

  • 클라이언트와 서버가 서로 연락을 절충하기 위해 주고받는 제어 정보
  • p.116에 나온 항목으로 규정되어 있다.
  • 헤더 : 제어 정보를 패킷의 맨 앞부분에 배치하는 곳부터를 헤더라고 한다.
  • 이더넷 혹은 IP의 제어 정보 + TCP의 제어 정보

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

  • 애플리케이션에서 통지된 정보, 통신 상대로부터 받은 정보 등이 수시로 기록된다.
  • 소켓에 기록한 제어 정보는 상대측에서 볼 수 없다.
  • 헤더에 제어 정보를 기록해 그것으로 대화한다.

 

3. 접속 동작의 실제

connect(<디스크립터>, <서버측의 IP주소 및 포트번호>, ...);
  1. connect 호출해, 명령이 프로토콜 스택의 TCP 담당 부분에 전달된다.
  2. 송, 수신 동작의 개시를 나타내는 제어 정보를 기록한 헤더를 생성한다.
    • 송신처와 수신처의 포트번호
    • 컨트롤비트인 SYN 비트를 1로 만든다.
    • SYN : 송신측과 수신측에서 일렬번호를 서로 확인하나. 이것으로 접속 동작을 나타낸다.
  3. IP담당 부분에 TCP 헤더를 건네주고, 송신하도록 의뢰하면, IP 담당 부분이 패킷 송신 동작 실행한다.
  4. 네트워크를 통해 패킷이 서버에 도착하면, 서버측의 IP 담당부분이 이것을 받아 TCP 담당 부분에 건네준다.
  5. TCP 담당 부분이 TCP 헤더를 조사해 기록된 수신처 포트번호에 해당하는 소켓을 찾아내,
    여기에 필요한 정보를 기록하고 접속 동작이 진행중이라는 상태가 된다.
  6. 이 과정이 끝나면, 서버측의 TCP 담당 부분은 똑같이 TCP 헤더를 만들어 응답을 돌려보낸다.
    • 송신처 및 수신처의 포트 번호
    • SYN 비트 1로 설정
    • ACK라는 컨트롤 비트도 1로 설정 : 패킷을 받은 것을 알리기 위한 동작
    • ACK : 수신 데이터의 일련번호 필드가 유효하다는 것을 나타낸다. 보통 데이터가 올바르게 수신측에 도착한 것을 나타낸다.
  7. TCP 헤더를 IP 담당 부분에 건네주어 클라이언트에 반송을 의뢰한다.
  8. 패킷이 클라이언트에 돌아오고, TCP 헤더를 조사해 서버 측의 접속 동작이 성공했는지 확인한다.
    • SYN이 1인경우 접속 성공이므로, 소켓에 서버의 IP 주소나 포트 번호 등과 함께 소켓에 접속 완료를 나타내는 정보를 기록한다.
  9. 패킷이 도착한 것을 서버에 알리기 위해 ACK 비트를 1로 만든 TCP 헤더를 반송한다.

TCP의 3-way Handshaking

이 패킷이 서버에 도착하면 접속 동작의 대화가 끝난다.
이렇게 소켓은 데이터를 송, 수신할 수 있는 상태가 된다.
이때 파이프와 같은 것으로 소켓이 연결되었다고 생각해라.
커넥션이 이루어지면, 프로토콜 스택의 접속 동작이 끝나므로, 애플리케애션을 제어할 수 있게 된다.

커넥션 : 이 파이프와 같은 것

  • close 호출하기 전까지 커넥션은 계속 존재한다.

 

데이터를 송,수신한다.


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

write 호출해 송신 데이터를 프로토콜 스택에 건네준고, 프로토콜 스택은 송신 동작을 실행한다.

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

  • 한 번의 송신 의뢰에서 건네주는 데이터의 길이는 애플리케이션의 사정에 따라 결정된다. 프로토콜 스택이 제어할 수 없다.
  • 받은 데이터를 바로 보내면, 데이터 송수신 동작이 지나치게 많이 일어나 네트워크 효율이 떨어질 수 있다.
  • 어느 정도까지 저장할지는 OS의 종류나 버전에 따라 달라진다.

언제 전송할지 판단 요소

  • 한 패킷에 저장할 수 있는 데이터의 크기
    • MTU : 패킷 한 개로 운반 가능한 디지털 데이터의 최대 길이
    • MSS : 헤더를 제외하고, 한 개의 패킷으로 운반할 수 있는 TCP의 데이터의 최대 길이
    • 애플리케이션에서 받은 데이터가 MSS를 초과하거나, 가까운 길이에 이르기까지 데이터를 저장하고, 송신 동작을 한다.
    • 그러나, 버퍼가 찰 때까지 기다리면  네트워크의 이용 효율은 높아지지만, 머무는 시간만큼 송신 동작이 지연될 우려가 있다.
  • 타이밍
    • MSS에 가깝게 데이터를 저장하면, 시간이 걸려 송신 동작이 지연된다.
    • 따라서 버퍼에 데이터가 모이지 않아도, 적당한 곳에서 송신 동작을 실행해야 한다.
    • 프로토콜 스택은 내부에 타이머가 있어, 이것으로 일정 시간 이상 경과하면 패킷을 송신한다.
    • 지연은 적어지지만,  이용 효율은 떨어질 수 있다.

양자를 절충해서 적당한 시간을 가늠해 송신 동작을 실행해야 한다.

이와같이 프로토콜스택에만 맡긴다면 좋지 않은 일이 발생할 수 있기 때문에
애플리케이션 측에서 송신 타이밍을 제어할 수 있다.

ex) '버퍼에 머물지 않고 바로 송신할 것' 이라고 지정

  • 프로토콜 스택은 버퍼에 머물지 않고 송신 동작을 실행한다.
  • 브라우저와 같이 대화형 어플리케이션은 서버에 메시지를 보낼 때 버퍼에 머무는 시간만큼 응답 시간이 지연된다.
  • 따라서 이 옵션을 사용하는 경우가 많을 것이다.

 

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

HTTP request 메시지는 보통 그다지 길지 않아 한 개의 패킷에 들어간다.
그러나 폼을 사용해 긴 데이터를 보낼 경우, 한 개의 패킷에 들어가지 않을 만큼 길 수 있다. (ex. 블로그 게시글 등)
이 경우 송신 버퍼에 있는 데이터를 앞부터 차례로 MSS 크기에 맞게 분할하고, 분할한 조각을 한 개씩 패킷에 넣어 송신한다.

 

3. ACK 번호를 사용해 패킷이 도착했는지 확인한다.

TCP는 패킷을 송신한 후에는 확인 동작으로 넘어간다.

시퀀스 번호

  • 패킷의 맨 앞에 위치의 데이터가 송신 데이터의 몇 번째 바이트에 해당하는지를 송신측에서 수신측에 전달하기 위한 것이다.
  • 데이터를 조각으로 분할할 때, 조각이 통신 개시부터 따져서 몇 번째 바이트 인지를 세어둔다.
  • 그리고 데이터를 송신할 때 세어둔 값을 TCP 헤더의 시퀀스 번호에 기록한다.

ACK 번호

  • 데이터가 몇 바이트까지 수신측에 도착했는지를 수신측에서 송신측에 전달하기 위한 것이다.
  • 수신 완료한 바이트 + 1

  1. 클라이언트와 서버가 서로 초기 시퀀스 번호를 주고 받는다.
    • 초기 시퀀스 번호를 악용할 수 있기 때문에 난수로 설정해 미리 주고 받는다.
    • 앞에서 SYN을 1로 설정해 송신하는데, 이것이 초기값을 통지하는 것이다.
  2. 클라이언트에서 서버에 시퀀스 번호와 데이터를 보낸다.
  3. 서버에서 데이터를 수신하면, '지금까지 수신한 바이트 + 1'값을 ACK로 지정해 응답한다.
    • 데이터 크기는 보낸 패킷에 헤더길이를 빼면, 수신한 길이를 유추할 수 있기 때문에 따로 기재하지 않는다..

*** 서버에서 클라이언트로 송신할때도 역으로 똑같이 동작한다.

  • 시퀀스 번호와 ACK 번호를 통해 누락된 패킷 여부를 알 수 있다.
  • TCP는 상대가 데이터를 받은 것을 확인할 때까지 송신한 패킷을 버퍼 메모리 영역에 보관한다.
  • 만일 송신한 데이터에 대응하는 ACK 번호가 오지 않았다면, 버퍼 메모리에 저장된 데이터를 재송신한다.
  • 만일 데이터를 아무리 다시 보내도 데이터가 도착하지 않는 경우에는,
    TCP는 몇 번 회복 전망이 없는 것으로 보고, 데이터 송신 동작을 강제로 종료하고 애플리케이션에 오류 통지를 한다.

 

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

  • 타임아웃 값 : ACK 번호가 돌아오는 것을 기다리는 시간

ACK 번호의 반송이 지연되는 것은 네트워크 혼잡이 원인인 경우가 많다.
만일, 대기시간이 지나도 오지 않아 재전송하면 혼잡을 악화시킬 수 있다.
그러나 대기시간이 너무 길어지면, 패킷을 다시 보내는 동작이 지연되어 속도 저하의 원인이 된다.

너무 짧지도 길지도 않은 적절한 값으로 설정하기 위해 TCP에선 대기 시간을 동적으로 변경하는 방법을 사용한다.

  • ACK 번호가 돌아오는 시간을 기준으로 대기 시간을 판단한다.
  • ACK 번호가 돌아오는 시간을 계측해둔다.
  • 돌아오는 시간이 지연되면, 대기 시간을 늘린다.
  • 곧바로 돌아오면, 대기 시간을 짧게 설정한다.

 

5. 윈도우 제어 방식(Sliding Window)으로 효율적으로 ACK 번호를 관리한다.

윈도우 제어

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

  • ACK 번호가 돌아올 때까지 아무일도 하지 않고 기다리는 것은 시간 낭비다.

주의할 점

수신측은 ACK 번호를 계산하거나 조각을 연결해 원래 데이터를 복원한 후 애플리케이션에 건네주어야 한다.
따라서 처리가 끝나지 않은 상태에서 다음 패킷이 도착하면, 수신 버퍼에 수신된 데이터를 일시 보관한다.

그러나, 애플리케이션에 건네주는 속도보다 수신되는 속도가 빠르면 수신 버퍼가 넘치고, 넘친 데이터는 사라진다.
이것은 수신측의 능력을 초과하는 것이다.

 

윈도우

TCP 헤더의 필드로, 수신측에서 송신측에 수신 가능한 데이터 양을 통지한다.

  • 수신 처리가 끝나고 수신 버퍼에 빈 부분이 생기면, 이것을 윈도우 필드에서 송신측에 알린다.
  • 이렇게 수신측의 능력을 초과하여 데이터를 보내는 일을 막을 수 있다.
  • 윈도우 사이즈 : 수신 가능한 데이터 양의 최대값

 

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

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

 

윈도우 통지의 타이밍

  • 윈도우의 값은 송신측이 데이터를 송신할 때마다 송신한 데이터만큼 감산하여 스스로 산출할 수 있다.
  • 윈도우 통지가 필요한 것은, 수신측이 수신 버퍼에서 데이터를 추출해 애플리케이션에 건네주었을 때다.

ACK 번호 통지의 타이밍

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

 

ACK 번호와 윈도우 통지의 패킷을 따로 송신측에 보내면, 수신측에서 송신측에 보내는 패킷이 많아져 효율성이 저하된다.

수신측은 ACK 번호나 윈도우를 통지할 때 소켓을 바로 보내지 않고 잠시 기다린다.
기다리는 사이 다음 통지 동작이 일어나면, 양쪽을 상승 시켜 한 개의 패킷으로 묶어서 보낸다.

  • 복수의 ACK 통지가 연속해 일어난 경우, 최후의 것만 통지하고 도중의 것은 생략해도 된다.
  • 윈도우 통지가 연속된 경우도 마찬가지로, 최후의 것만 통지하면 된다.

 

7. HTTP 응답 메시지를 수신한다.

  • HTTP 리퀘스트 메시지를 보내면, 웹 서버에서 응답 메시지가 돌아오기를 기다리고, 돌아오면 그것을 수신한다.
  • 브라우저는 리퀘스트 메시지 송신을 의뢰하고, 응답 메시지를 받기 위해 read 프로그램을 호출한다.
  • 데이터를 수신할 때, 수신 버퍼에 데이터를 일시 보관한다.
  • 수신 데이터에 TCP 헤더 정보를 통해 누락된 데이터를 확인하고, ACK를 응답한다.
  • 수신 버퍼에서에 보관된 데이터 조각을 연결해 데이터를 원래 모습으로 복원한 후,
    애플리케이션이 지정한 메모리 영역에 옮겨 기록한다.
  • 타이밍을 가늠해 윈도우를 송신측에 통지한다.