TCP의 작동 방식

2023. 4. 6. 13:00네트워크

네트워크 계층별 데이터 단위
L1~L2: Frame
L3: Packet - Packet의 최대 크기: MTU(Maximum Transmission Unit) = 1500byte (MSS + TCP Header(20) ,IP Header(20))
L4: Segment - Segment의 payload 최대 크기: MSS(Maximum Segment Size) = 1460byte.
TCP Socket: Stream(연속적으로 이루어진 크기가 큰 데이터), 이 Stream을 MSS 단위로 잘라서 Segment들로 만든다.
참고로 UDP는 Datagram 단위이다.

TCP 헤더

TCP 헤더의 Sequence Number, Acknowledgement Number
Sequence Number: 보낸 데이터의 순서, 즉 현재 데이터 시작 위치(이전 SEQ NUM + 이전 데이터 크기)를 기록한 것. 이를 통해 TCP의 연결 개념을 구현한다. 처음 SYN을 보낼 때, SEQ NUM의 초기값을 알려준다. 이 초기값은 임의의 숫자이고, 추후 보내는 패킷들의 SEQ NUM 값은 이 값에서 계속 더해지는 방식으로 만들어진다.
Acknowledgement Number: 보낸 데이터를 받았다는 것을 송신처에 알려준다. 받은 SEQ NUM+ 데이터(payload)의 크기를 합친 것이 ACK 값이 된다. 다만, 데이터 크기가 0일 경우에, 받은 SYN 값에 1을 더한 값이 ACK 값이 된다. 그냥 SEQ NUM 값을 그대로 보내면, 이전 ACK와 같은 값이 되므로, ACK를 받는 측에서 데이터를 상대가 잘 받았는지 구별할 수가 없기 때문이다.
 
네트워크 플래그
SYN: 초기 시퀀스 번호 보낼 때(세션 연결 시) 플래그
ACK: ACK 값 보낼 때 플래그
FIN: 정상적인 세션 연결 종료 시 플래그 
RST: 비정상적인 세션 연결 끊기. 보내는 측에서 즉시 연결을 끊고자 할 때 사용한다.
PSH: 송신 버퍼가 채워지지 않아도 기다리지 않고 데이터를 전달한다. (flush 동작에 의해 송신된 데이터임을 나타낸다.)
수신측에서는 PSH 플래그가 있는 패킷을 받으면, 이 데이터를 버퍼에 쌓지말고 바로 응용 계층으로 넘긴다.
Send 과정의 끝에 PSH 플래그가 붙는다. (마지막이니까 L7으로 올리라는 것.)
URG: Urgent Pointer가 유효한 것인지 나타냄. 사용하지 않는다.
 
TCP 흐름제어 : 송신측과 수신측의 데이터 처리 속도 차이를 해결하기 위한 기법, 수신측이 패킷을 지나치게 많이 받지 않도록 조절한다. 
매번 전송한 패킷에 대해 확인 응답(ACK)을 받고나서 패킷을 전송한다면 매우 비효율적일 것이다.(Stop and Wait 기법)
따라서 Sliding Window 방식을 사용한다. 수신측에서 설정한 Window Size만큼을 송신측에서 확인응답없이(ACK 없이) 전송할 수 있게하여 데이터의 흐름을 동적으로 조절하는 기법이다.
수신측의 Window Size 이하의 송신측 윈도우를 형성하고, 이 윈도우에 포함되는 모든 패킷을 전송한다.
이 패킷들의 전달이 확인되는대로 윈도우를 옆으로 옮기면서 다음 패킷들을 전송한다.
 
Window Size, Window Scale
Window Size는 수신 버퍼의 남은 크기를 나타낸다.
이때, Window Size를 나타내는 공간이 16byte이기 때문에, 최대 65535Byte, 즉 64KB를 나타낼 수 있는데
그렇다면 송신 측에서 ACK 수신 전까지 최대 64KB만 보낼 수 있다. 특히 이 경우에 네트워크 연결된 상대방과의 RTT가 느리다면 더욱 속도가 느려질 것이다.
따라서 TCP의 속도를 키우기 위해서 Window Scale 옵션이 존재하고, 이 옵션은 초기의 SYN 패킷에만 존재한다.
2^(Window Scale 옵션 값)을 Window Size에 곱한 것이 실제 Window Size가 된다.
 
Nagle 알고리즘: 송신 버퍼에 MSS이상 쌓이거나, 상대방 ACK가 왔을 경우에 송신한다. 기본적으로 TCP에서 사용.
장점: 작은 패킷이 불필요하게 생성되는 것 방지
단점: ACK 대기 시간때문에 반응 시간이 길어질 수 있다.
TCP_NODELAY 옵션을 통해 이 알고리즘의 작동을 막을 수 있다 > 송신 버퍼에 MSS만큼 안쌓여도 바로 보내게.
 
L7에 버퍼를 두는 이유: TCP 송수신 버퍼의 send/recv call이 느리기 때문에 횟수를 줄이기 위해서.
recv 시 데이터가 뭉쳐져 있었다면 원인:
1. 네이글 알고리즘, 2. L7에서 recv를 늦게 받아서, 3. 윈도우 사이즈 부족
recv 시 데이터가 쪼개져 있었다면 원인:
1. 이전 패킷의 MSS 도달, 2. 윈도우 사이즈가 일부분만 남아있어서, 3. L7에서 수신 버퍼 크기를 적게줘서.
>실제 통신 환경에서 대부분은 L7의 문제다.


클라이언트 소켓과 서버 소켓의 실행 흐름은 아래 그림과 같다.

출처: https://recipes4dev.tistory.com/153

 

 


TCP 연결 과정: 3-way handshaking

출처: https://sjlim5092.tistory.com/35

관련 소켓 함수

Client: Connect() 호출 시 SYN 보냄, SYN/ACK 수신 시 connect() return됨.

Server: accept() 호출 시 SYN을 받고, SYN/ACK를 보냄. ACK 도착 시, accept() return됨.

절차
1. Client > Server로 SYN 패킷을 전송. (Client: SYN_SENT, Server: Listen > (수신시)SYN_RCVD)
2. Server > Client로 SYN+ACK 패킷을 전송 (Client: SYN_SENT > (수신시)ESTABLISHED, Server: SYN_RCVD)
3. Client > Server로 ACK 패킷을 전송. (Client: ESTABLISHED, Server: (수신시)ESTABLISHED)

연결 시에 문제가 발생했다면

1. Client 소켓 상태가 SYN_SENT에서 멈췄는지 확인(netstat 명령) & 방화벽, L3계층 정상적으로 작동하는지 확인

2. 서버 소켓의 상태(Listening 상태인지), 방화벽 정상적으로 작동하는지 확인

3. 코드 확인

 

TCP 연결 종료 과정: 4-way handshaking

출처: https://beenii.tistory.com/127

관련 소켓 함수

close() 함수 호출시 FIN을 보낸다.

절차
1. Client > Server로 FIN 패킷을 전송. (Client: ESTABLISHED > FIN_WAIT1, Server: ESTABLISHED)
2. Server > Client로 ACK 패킷을 전송. (Client: FIN_WAIT1 > (수신시)FIN_WAIT2, Server: ESTABLISHED > CLOSE_WAIT)
3. Server > Client로 FIN 패킷을 전송. (Client: FIN_WAIT2 > (수신시)TIME_WAIT, Server: CLOSE_WAIT > LAST_ACK)
4. Client > Server로 ACK 패킷을 전송. (Client: TIME_WAIT > (일정시간 대기 후)CLOSED, Server: LAST_ACK > (수신시)CLOSED
(*TCP 연결 종료를 요청한 쪽에서 TIME_WAIT이 발생하기 때문에, 클라이언트 측에서 연결을 끊게 해야 서버가 TIME_WAIT이 걸리지 않는다.)
연결 종료 과정 중 문제 발생하는 경우
FIN_WAIT1에서 멈춘 경우: 상대 OS의 문제 or 네트워크 유실
FIN_WAIT2에서 멈춘 경우: 상대 Application에서 FIN을 보내지 않았다.
 
목적지 PC에 도착 후 패킷 처리 과정
인터럽트로 CPU에 패킷 도착을 알림 > CPU가 실행을 LAN 드라이버로 전환 > 버퍼 메모리의 수신 패킷 추출 > 프로토콜 판별 > 프로토콜 처리 SW(IP) > IP헤더를 보고 목적지가 맞는지 확인(자신의 것이 아니면 중계 or 폐기) > 조각 나누기를 조사(나눠져있으면 임시 보관) > TCP 계층에 넘겨줌 > 
1) SYN 패킷일 경우
listen소켓 확인 > SYN,ACK,Window Size 정보 전송
2) 데이터 패킷일 경우
송신IP/PORT, 수신 IP/PORT 일치하는 소켓을 찾는다 > 송수신 진행상황 점검(sequence 번호) > 수신 버퍼에 저장 > ACK 전송

네트워크 문제의 원인
loss, Re-transmission(ACK-Duplicate) : 네트워크 문제(버퍼 초과, 외부간섭) 혹은 응용계층의 문제 (응용계층에서 처리를 다 못하는..)
Out of order(패킷 순서가 다르게 도착) : 네트워크 문제, 일정 수준은 OS에서 보정해준다.
Zero-window : 수신처에서 수신 버퍼의 데이터를 빨리 가져가지 못했기 때문에 발생. 

'네트워크' 카테고리의 다른 글

네트워크 작동 방식  (1) 2023.02.01
OSI 7 계층, TCP/IP 4 계층  (0) 2023.02.01