[Network] TCP/IP
TCP: 연결 지향
Stream Delivery
TCP: byte stream
UDP: bound delivery
Sequence Number
- TCP 세그먼트의 연속된 번호
- random
ACK
1. Selective ACK
-> 받은 데이터의 시작 번호를 반환
2. Cumulative ACK
-> 받은 데이터의 다음 번호를 반환
TCP segment format
- Header: 20 ~ 60 bytes
16 bit: src port address
16 bit: dst port address
32 bit: sequence number
32 bit: acknowledge number
4 bit: HLEN
6 bit: reserved
6 bit: Flag
16 bit: window size
16 bit: checksum
16 bit: urgent point
options
주요 Flag
1. ACK
2: SYN
3. FIN
Chekcsum
- TCP에서는 필수 요소
- IP header에 존재하는 16 bit TCP total length도 포함하여 진행
-> 해당 pseudoheader를 보내지는 않음
Three way handshake
1. Establish
client: SYN 전송 / random seq 포함하여 전송
server: SYN + ACK 전송 / random seq, 이전에 받은 seq + 1의 ack, rwnd 포함하여 전송
client: ACK 전송 / 이전에 받은 seq + 1의 ack, rwnd 전송
- SYN, ACK은 데이터를 포함하지 않음
- UDP는 이런 셋업 과정 X
2. Terminate
client: SYN + FIN 전송
server: FIN + ACK 전송
client: ACK 전송
만약 server의 응답 중
FIN, ACK 응답의 시간이 길면 4 way handshake라고도 보는 경우가 있음
Half Close
- server가 보낸 데이터를 송신 가능, 수신 불가
Timeline diagram
client가 SYN을 보낸 상황 = SYN-SENT, server = LISTEN
server가 SYN + ACK을 보낸 상황 = SYN_RCVD
client가 ACK을 보낸 상황 = ESTABLISHED
...
client가 FIN을 보낸 상황 = FIN-WAIT1
server가 ACK을 보낸 상황 = CLOSE-WAIT
server가 FIN을 보낸 상황 = LAST-ACK, 그 전까지 client = FIN-WAIT2
client가 ACK을 보낸 상황 = TIME-WAIT
=> 2MSL로 1 ~ 2분을 기다림.
=> server가 ACK을 받지 못한 경우 FIN을 다시 보낼 것이므로 기다리기 위한 시간
Fin이 전송되는 경우
1. close() 함수 호출
2. 프로세스가 종료될 때
3. ctrl + c로 강제 종료
-> server가 time-wait 상태로 감
TCP 서버의 함수 호출 순서
1. socket() -> 소켓 생성
2. bind() -> 소켓 주소할당
3. listen() -> 연결 요청 대기 상태
4. accept() -> 연결 허용
5. read() / write() -> 데이터 송수신
6. close() -> 연결 종료 => FIN이 전송
FLOW CONTROL (흐름 제어)
첫 번째 ACK이 오기까지 얼만큼의 데이터를 보낼 수 있을
-> 상대방이 받을 수 있을만큼
-> 시시각각 변함
Window size = min (rwnd, cwnd)
ack 기준 다음 버퍼부터 전송
-> 속도는 TCP가 조절
Silly Window Syndrome
헤더 크기에 비해 보낼 데이터가 비효율적으로 적은 경우
1. 송신
Nagle algorithm
1) 보낼 데이터가 MSS만큼 쌓이면 전
2) MSS보다 작을 경우 ACK이 오면 전
default = ON
delay가 민감하면 Nagle OFF, 아니라면 ON
2. 수신
1) Clark: MSS만큼의 빈 공간이 생길 때 까지 | buffer 공간의 절반이 남았을 때까지 rwnd = 0으로 전송
2) ACK 전송 지연
SYN Flooding
client가 임의의 주소로 server에 SYN을 보냄
-> server는 연결 요청 대기 큐에 넣음
-> SYN + ACK을 계속 client에 보내나 돌아오는 ACK이 없음
-> 계속해서 기다리므로 지연 발생
-> DOS (SYN Flooding)
=> Distributed Denied of Services == DDoS
사용자가 본인의 주소를 가짜 주소로 바꾸어 서버에게 대량의 SYN을 보내면
서버는 SYN + ACK을 보내고 연결요청 대기 큐에 넣음
-> 돌아오는 ACK이 없으므로 정상적인 연결이 안됨
=> SYN Flooding
ERROR CONTROL
TCP는 신뢰성을 보장
Rule 1
: sending buffer를 봐서 보낼 데이터가 있다면 헤더에 ACK을 실어서 보내자
Rule 2
: buffer를 봤는데 보낼 데이터가 없다면 50ms를 기다리고 ACK을 보냄
Rule 3
: 들어온 데이터가 2개라면 ACK을 하나 보냄
-> 두 당 하나
Rule 4
: Out of order (응급 상황)이므로 ACK을 바로 보냄
Rule 5
: 빈 공간이 채워지면 다시 다음 ACK을 보냄
패킷 로스 확인: 패킷마다 timer를 켜고, timer가 지나도 ACK이 없으면
fast retransmission
: 세 개의 중복된 ACK이 도착하면 time out까지 가는 것이 아니라 바로 패킷 로스로 간주
-> 빠르게 재전송함
-> fast인 이유: time out까지 도달하지 않음
-> RTO를 길게 잡아야 함
cumulative 방식: 패킷 로스의 여부를 확인할 수 없음
로스 된 이후의 패킷을 한 번에 다 보냄
ex) 301 ~ 801이 전송 되었으나 301이 안보내졌고,
ACK 301이 3번 전송되면 fast restransmission에 의해
301 ~ 801을 다시 전송
Rule 6
: 받은 패킷이 오면 그 이후 받고 싶은 ACK을 다시 보냄
deadlock
server -> client로 최종 ACK을 보냈으나, 이것이 누락된 경우 하염없이 기다림
Persistent Timer
교착 상태를 해결하기 위해 사용
-> 영속 타이머가 만료되면 probe 세그먼트 전송
CONGESTION CONTROL
TCP1 100Mbps, TCP2 100Mbps -> 총 200Mbps를 전송
라우터에서는 100Mbps만 감당 가능
-> 혼잡한 상황
cwnd: sender가 관리
additive increase, congestion avoidance
-> 혼잡 구간이 아닌 곳에서 혼잡 발생을 방지
중앙 통제가 없으므로 얼만큼 보내야하는지 잘 모름
-> 보내는 양을 조금씩 늘려감
-> 어느 순간 혼잡이 발생-> 보내는 양을 절반으로 줄임
slow start, exponential increase
만약 100차선처럼 많으면
천천히 100까지 늘려가야하므로 오래걸림
-> 두 배씩 늘리자
=> slow start, exponential increase
flow control과 비교했을 때 느리므로
threshold까지 도달하면 두 배씩 증가를 중단, packetloss가 발생해도 증가 중단
처음 연결 -> slow start -> 두 배씩 증가시키다가
threshold를 만나면 stop
이후 consgestion avoidance에서 additive increase 진행
혼잡이 발생하면 cwnd를 반으로 줄여 다시 additive increase를 진행
packetloss -> 혼잡으로 받아들이는 이유
-> 혼잡에 의해 packet을 버리는 경우가 많음
RTT vs RTO
RTT: Round Trip Time
-> 패킷의 응답까지 걸리는 시간
RTO: Retrun Time Out
-> 데이터 전송 후 재전송을 위해 걸리는 시간
AIMD
Additive Increase Multiplicative Decrease
time out이 발생하면
window size를 1부터 시작
slow start를 진행
-> threshold가 필요
timeout이 발생했을 당시의 window size의 절반을 새로운 threshold로 사용
두 배씩 커지다 threshold에서 stop
slow start가 없었을 때 flow control로 관리
과거에는 2^16인 65000바이트를 한 번에 쏟아냄
TCP Fair
계속해서 혼잡이 발생한다면 두 연결은 절반으로 줄어드므로 결국 throughput은 50 : 50이 될 것이다.
만약 두 연결의 RTT가 다르다면 기울기가 달라질 것이다.
Timers
Retransmission
retransmission timer에 의해 packet loss를 detect하면 slow start로 들어감
1) persistence timer
- rwnd를 0으로 받은 경우 timer를 켜서 probe segment를 전송
- rwnd와 ack이 넘어옴
deadlock 상황: rwnd !=0 인 패킷이 전송되지 않은 경우
2) keepalive timer
- 오랜 기간 idle 상태에 있는 것 방지
- 서버가 2시간 동안 클라이언트로부터 세그먼트를 전송받지 못했다면, probe segment를 전송
Smoothed RTT
첫 번째 측정 이후 RTTs = RTTm
그 이후 RTTs = 7/8 * RTTs + 1/8RTTm
RTT Driven
첫 번째 측정 이후 RTTd = RTTm / 2
그 이후 RTTd = 3/4RTTd + 1/4|RTTs - RTTm|
RTO
RTO = RTTs + 4 * RTTd
초기 RTO = system에서 설정한 값
ex)
SYN을 보내고 SYN + ACK이 오기까지 1.5가 걸린 경우
- RTTm = 1.5
- RTTs = RTTm = 1.5
- RTTd = RTTm / 2 = 0.75
-> RTO = RTTs + 4 * RTTd = 4.5
이후 데이터를 전송하고 ACK이 오기까지 2.5가 걸린 경
- RTTm = 2.5
- RTTs = 7/8RTTs + 1/8RTTm = 1.625
- RTTd = 3/4RTTd + 1/4|RTTs - RTTm| = 0.78
-> RTO = RTTs + 4 * RTTd = 4.74
Karn's Algorithm
재전송 되는 경우 응답이 RTO 이후에 도착하는 경우도 존재
-> RTT 계산 X
-> 정상적인 패킷 전송 이후 다시 계산 시작
-> 재전송시 RTO = RTTs + 4 * RTTd가 아닌 2 * RTO로 계산
OPTIONS
- single byte
- multiple byte
1) 3-byte option
- EOP (End Of Option): 한 번만 사용 가능 / 맨 뒤에 존재
- NOP (No Operaton Option): 여러번 사용 가능 / 앞에 존재
2) Maximum Segment Size (4 byte)
- sender, reciever가 상의하여 조절 가능
- setup 과정에서 합의해야 함
- 중간에 변경 불가능
3) scale - factor (3 byte)
- setup 과정에서 약속
ex) RTT = 1초의 throughput
rwnd = 1111...11인 경우 최대 2^16 byte
2^16 byte = 2^10 * 2^6 byte = 64KByte
64KByte / s = 64 * 8bits / s = 512Kbps = 0.5Mbps
ex) RTT = 100ms
64KByte / 0.1s = 5Mbps
-> 사이즈를 2^n만큼 키우고 싶음 -> scale factor에 n 저장
if) rwnd = k라고 왔다면, k * 2^n으로 인지
4) time stamp option
- RTT 측정시 사용
-> option에 출발 시간을 적어 보낸 것을 바탕으로 상대방이 ACK을 보낼 때 출발 시간을 적어서 보냄
-> RTT를 계산
- PAWS (Protection Against Wrapped Sequence number)
-> sequence number가 random이지만, 일치할 가능성 존재
-> time stamp를 통해 언제 전송된 패킷인지 구분
5) SACK
- setup 과정에서 약속
- 중간에 loss된 경우 해당 패킷 이후 모두 전송이 비효율적
- cumulative의 단점인 이후의 상황 보완
- 블럭을 생성
- 받은 시작 주소 ~ 마지막 주소 + 1을 저장
- 첫 번째 블록에는 중복된 내용을 기입할 수도 있음