티스토리 뷰

TCP/IP 없는 인터넷 서비스는 상상할 수 없다. 우리가 개발하고 사용하는 모든 인터넷 서비스는 TCP/IP라는 토대에 기반하고 있다. 

어떻게 네트워크를 통해 데이터가 오가는지를 이해하면, 튜닝 등을 통한 성능 개선이나 트러블 슈팅, 신기술 도입 등에 많은 도움이 된다. 

TCP/IP의 중요한 성질

데이터의 순서가 바뀌지 않으면서 데이터가 유실되지 않도록 가급적 빠르게 데이터를 보내려면 네트워크 프로토콜을 어떻게 설계해야 할까? TCP/IP는 이런 고민 아래 설계된 것이다. 

TCP와 IP

엄밀히 말해 TCP와 IP는 서로 다른 레이어의 것이라 분리해서 이해하는 것이 옳지만, 이해의 편의상 여기서는 이 장에서는 둘이 분리하지 않고 설명한다. 

  1. Connection oriented
    • 두 개의 엔드포인트(로컬, 리모트) 사이에 연결을 먼저 맺고 데이터를 주고받는다. 여기서 'TCP 연결 식별자'는 두 엔드포인트 주소를 합친 것으로, <로컬 IP주소, 로컬 포트번호, 리모트 IP주소, 리모트 포트번호> 형태
  2. Bidirenctional byte stream 
    • 양방향 데이터 통신을하고, 바이트 스트림을 사용한다.
  3. in-order delivery
    • 송신자(sender)가 보낸 순서대로 수신자(receiver)가 데이터를 받는다. 이를 위해서는 데이터의 순서가 필요하며 순서를 표시하기 위해 32-bit 정수 자료형을 사용한다.
  4. Reliability through ACK
    • 데이터를 송신하고 수신자로부터 ACK(데이터를 받았다는 메세지)를 받지 않으면, 송신자 TCP가 데이터를 재전송한다. 따라서 송신자 TCP는 수신자로부터 ACK를 받지 않은 데이터를 보관한다(buffer unacknowledge data).
  5. Flow control
    • 송신자는 수신자가 받을 수 있는 만큼 데이터를 전송한다. 수신자가 자신이 받을 수 있는 바이트 수(사용하지 않은 버퍼 크기, receive window)를 송신자에게 전달한다. 송신자는 수신자 receive window가 허용하는 바이트 수만큼 데이터를 전송
  6. Congestion control
    • 네트워크 정체를 방지하기 위해 receive window와 별도로 congestion window를 사용하는데 이는 네트워크에 유입되는 데이터양을 제한하기 위해서이다. reveive window와 마찬가지로 congestion window가 허용하는 바이트 수만큼 데이터를 전송하며 여기에는 TCP Vegas, Westwood, BIC, CUBIC 등 다양한 알고리즘이 있다. Flow control과 달리 송신자(서버)가 단독으로 구현한다. 

데이터 전송

네트워크 스택에는 여러 레이어(layer)가 있다. 어떤 레이어가 있는 지는 그림에서 확인 가능하다. 

데이터 전송 시 TCP/IP 네트워크 스택의 각 레이어 별 동작 과정

여러 레이어가 있지만, 크게 유저(user) 영역, 커널(kernel) 영역, 디바이스(device) 영역으로 나눌 수 있다. 

유저 영역과 커널 영역에서의 작업은 CPU가 수행한다. 이 유저 영역과 커널 영역은 디바이스 영역과 구별하기 위해 호스트(host)라고 부른다. 여기서 디바이스는 패킷을 송수신하는 NIC(Network Interface Card)이다. 흔히 부르는 랜카드보다 더 정확한 용어이다.

(내용 중략)

상세 내용은 원문을 참고하여 확인 링크주소: Naver D2 : TCP/IP 네트워크 스택 이해하기 


TCP/IP 동작원리 설명

상황: 클라이언트 PC와 서버PC가 TCP/IP 연결(3-way handshake)을 해두고 통신(파일 다운로드)을 한다.

 

서버측

서버의 web server(본질적으로 Process) 라고 가정했을 때, socket이 열려서 소켓으로 클라이언트와 통신하고 있음

(socket의 본질은 file이다, 그렇기 때문에 소켓이 할 수 있는 것은 Read, Write 동작 뿐) 

해당 Process를 추상화 시킨 것이 Socket이다.

소켓에서 Read -> Receive(속도) , Write -> Send

즉, 서버 Process 가 Socket에 I/O를 한다고 보면 된다. 

이 Socket에는 기본적으로 Buffer가 있다. 

메모리의 다른 말은 Buffer(버퍼)

이해하면 인생이 바뀌는 TCP 송/수신 원리 #1 서버측 상황

Buffer #1에 올라간 파일 조각이 TCP에 있는 Buffer #2에 복사된다.

Socket에 Buffer가 있고 TCP에도 Buffer가 있다. 총 2개의 Buffer가 있는 것이다. 

Buffer #2에 올라간 파일 조각은 IP로 내려가게 되는데 이를 Segment 라고 부르며 해당 Segment 는 파일조각을 쪼개 번호를 붙인 형태로 생각하면 된다. Packet(패킷)은 택배 박스와 유사한 개념이라 보면 되는데 Packet은 하나의 Segment 를 넣어준 택배박스라고 생각하면 된다. 

Segment가 담긴 패킷이 인터넷을 타고 클라이언트 PC쪽으로 날라가게 되는데 해당 패킷이 IP에서 NIC(L2수준)으로 내려올 때는 패킷을 Frame(프레임)이라고 부른다. 

NIC (Network Interface Card, a.k.a. 랜카드), NIC를 움직이는 것은 Driver(Device Driver)이다. 그 위에 TCP/IP 프로토콜 스택이 있다.

 

패킷을 택배박스라고 했을 때 택배박스를 수송해줄 택배차라 있을 것인데 이 택배차를 Frame이라고 생각하면 된다. 배달 기사는 해당 패킷의 사이즈나 내용물에는 상관없이 그냥 옮겨주는 것이 목적이며 한번에 도착지로 가는 것이 아니라 클라이언트 라는 목적지를 가기 위해서는 여러 트럭을 거칠 것이다. 즉, 서버PC에서 보낸  Frame은 A버스를 통해 보낸 것이지만 클라이언트 PC쪽에 도착하는 버스는 C버스일 것이다.  

 

클라이언트 PC는 서버 PC와 동일하게 구조를 가지고 있는데 클라이언트 Socket에는 해당 파일과 연결된 File I/O Buffer가 있다. 그리고 클라이언트 TCP에는 TCP Buffer가 있을 것이다. 

프레임은 택배기사가 IP 수준에 도달했을 때, decapsulation이 일어난다. 택배상자를 Packet이라고 했으니 IP수준에서는 packet이었다가 TCP 수준에서는 택배 상자가 뜯겨 Segment가 된다. 

1번 segment가 TCP Buffer에 붙고 이후 2번 segement가 도착하여 대략 2번정도의 segment가 TCP Buffer에 존재하게 됐을 때, TCP는 어떤 동작을 하게 된다. ACK에 #3이라는 서버에 데이터를 잘 받았다는 수신 알림을 보내는데 이 의미는 1번, 2번 데이터 잘 받아서 붙였으니까 3번 보내! 라는 뜻이다.  

클라이언트가 서버에 잘 수신했음을 알리는 것을 ACK라고 한다. 이때, 번호를 붙여 서버에 알려주게 된다. 
🐱‍👤ACK, 응답 문자, 승인 코드(acknowledgement code)는 승인을 서명하거나, 응답을 보내기 위해, 통신 프로토콜의 일부로서 통신 프로세서나 컴퓨터 사이를 지나가는 신호이다.

서버에서는 1번, 2번 segment 를 보내고 3번을 바로 보내는 것이 아니라 Wait하는데 wait을 하면서 ACK를 기다리는 것이다. 이 Wait 행위 때문에 속도 지연이 발생한다.  (TCP가 UDP보다 느리다 라는 통설은 이 이유때문이다. 다른 부가적인 이유가 있지만 핵심 이유라고 한다.)

이해하면 인생이 바뀌는 TCP 송/수신 원리 #1 클라이언트 쪽 상황

이렇게 받아온 1,2 번 세그먼트를 붙이고 남은 공간을 "Window Size"라고 하는데 이는 수신측에서 Segment가 날라오면 조립해서 넣을 수 있는 공간을 의미한다. ACK에는 다음 데이터의 숫자와 함께 Window Size를 같이 보내게 되는데 서버에서 해당 Window Size를 ACK를 통해 확인했을 때, #3 세그먼트가 들어갈만한 공간이 없으면 서버에서 클라이언트로 데이터를 보내지않는다.

즉, 수신측의 Window Size가 MSS(맥시멈 세그먼트 사이즈, 서버에서 보내려고 하는 다음 세그먼트) 보다 큰 지를 송신측에서 확인하여 충분히 크다면 데이터를 Send 하고 아니라면 Wait가 걸린다. 

 

클라이언트 소켓의 Read 속도는 Netword 수신 속도보다 빨라야 한다.

TCP 버퍼의 받아온 Segment 뭉탱이를 Socket의 File I/O Buffer로 올려주는데 이 과정을 Read라 칭하는거 같고 이 Read속도는 조합된 segment 를 소켓 Buffer로 올리는 속도를 칭한다.

클라이언트의 읽어들이는 속도가 너무 느리면 TCP Buffer의 window size가 점점 줄어들게 된다. 택배상자에서 깐 segment가 TCP Buffer에 올라가게 되는데 한정된 메모리 공간(Buffer)에서 Socket의 Buffer로 넘어가지 못하고 적재되기 때문이다. 

즉, 클라이언트 소켓의 Read라는 것은 TCP 버퍼에서 결합된 segment조각을 socket의 버퍼로 올리는 과정을 말하는 거 같다.

 

위와 같은 논리로 장애가 발생했을 때, 네트워크에서 장애 원인을 찾는 것이 아니라 클라이언트 프로그램에서 찾아야 한다.

수신이 느리다는 것은 송신이 느리다는 뜻인데 무조건 서버가 느려서 그런 것이 아니라 클라이언트가 받을 준비가 안됐을 수도 있을거라는 가정을 할 수 있어야 한다. 

TCP/IP의 경우에는 송신보다 수신쪽에서 에러가 나는 경우가 많기때문에 명심해야 한다. 

all Ref:  이해하면 인생이 바뀌는 TCP 송/수신 원리 [널널한 개발자 유튜브]

 


연결지향형 TCP 프로토콜 - TCP 3way handshake 

 TCP를 이용한 통신과정 

⭐연결 수립 과정

TCP를 이용한 데이터 통신을 할 때 프로세스와 프로세스를 연결하기 위해 가장 먼저 수행되는 과정

  1. 클라이언트가 서버에게 요청 패킷을 보내고(항상 요청은 클라이언트가 -> 서버에게)
  2. 서버가 클라이언트의 요청을 받아들이는 패킷을 보내고(수락하고 서버가 다시 클라이언트에게 나도 너한테 요청해도 돼?)
  3. 클라이언트는 이를 최종적으로 수락하는 패킷을 보낸다.

위의 3개의 과정을 3way Handshake라고 부른다. 

 

대표적인 웹 서버 예시) 아파치, 톰캣, 엔진엑스

  • 다음, 네이트 (웹서버: 아파치)
  • 네이버(웹서버: 엔진엑스)

클라이언트(e.g. 크롬)가 웹 서버에 TCP를 만들어서 보낸다. 이때, TCP정보는 캡슐화되어 보내진다. 포트 번호는 웹이기 때문에 80일 것이고.. 이 TCP에는 시퀀스 번호와 ACK번호가 세팅되어있고, flag 등 여러가지 정보가 담겨있다. 웹 서버는 클라이언트로 요청받은 것(TCP)을 디캡슐레이션하여 내용을 확인하는데 flag값이 SYN(싱크)이므로 이 내용을 보고 연결요청을 알아차린다. 웹 서버는 다시 클라이언트에게 요청을 보내는데 이때 Flag는 SYN + ACK 그리고 새로운 시퀀스 번호와 ACK 번호를 세팅하여 보낸다. 클라이언트는 ACK를 통해 "내가 요청한 것에 대한 답변이 왔군" 하고 확인한다. 그리고 같이 온 SYN를 통해 "서버도 나에게 연결하고 싶다고 요청하는 군" 하고 알아차린다. 

마지막으로 클라이언트가 웹 서버의 요청에 대한 대답으로 Flag를 ACK와 시퀀스 넘버와 ACK 번호를 넘겨준다. (클라이언트와 웹 서버를 연결하는 과정이므로) 이 과정이 3가지 단계로 이루어져 있기 때문에 3 way handshake라고 부르는 것이다. 

인캡슐레이션과 디캡슐레이션은 그냥 요청을 보낼때는 요청메세지를 인캡슐레이션(캡슐화)하는 것이고 요청을 받는 쪽이 디캡슐레이션을 하는 것이다. 클라이언트는 항상 인캡슐레이션을 하고 웹 서버는 항상 디캡슐레이션을 하는 것이 아니라 양쪽에서 두 가지 행위가 가능하다. 
댓글