3. OSI Arghitecture L4
◆ [L4] Transport 계층
에러 검출 및 복구, 흐름 제어, 혼잡 제어
process-to-process 통신
이제 메세지는 L3을 거쳐 내 컴퓨터 안에 들어왔다. 그럼, 컴퓨터 위에서 실행중인 많은 프로세스들 중에 어느 프로세스로 보내야 할지를 결정해야 할 것임.
→ L4에서 port 번호를 통해 process를 식별하도록 한다. (L3은 ip주소를 통해 host를 식별했고, L2는 MAC주소를 통해 node를 식별했다.)
< Transport 계층에서 Port 번호가 갖는 의미 >
- 포트는 운영체제 위에 올라온 여러 프로그램과 운영체제 사이의 연결 구멍으로,
포트 번호를 통해 어떤 프로세스를 유일하게 식별할 수 있다. - 포트 번호는 0~65,535까지 존재하는 16비트 정수이다.
- 0~1,023까지는 잘 알려진 포트 번호로, 운영체제나 기본 서비스에서 쓰이는 고정된 포트번호이다. - 메세지는 IP주소에 의해서 컴퓨터나 장치에 도달하고, 운영체제는 이를 받아서 메세지의 destination 포트 번호에 해당하는 프로세스에게 전달한다.
- L4는 L5로부터 받은 페이로드에 어떤 프로그램이 보낸 것인지를 알 수 있도록 포트 번호 대한 헤더를 붙이고,
L3은 L4로부터 받은 페이로드에 다시 IP주소에 대한 헤더를 붙이고 .. 이런 식으로 쭉 내려간다.
◆ Socket Address
Socket Address는 해당 컴퓨터의 특정 프로그램을 유일하게 식별할 수 있는 주소이다.
소켓 주소는 IP Address + Port Number로 구성되어있다.
◆ Connectionless vs Connection-Oriented
통신하는 프로그램 간 논리적인 연결을 하느냐에 따라 구분
L4라 해서 무조건 에러 제어나 흐름 제어 하는 건 아니다.
통상 얘기하는 레이어 기능들은 여기서 이런거 하면 좋다~ 라는 거고. 실제 구현하는건 개발자의 몫임.
- Connectionliess (UDP)
: 프로그램 간 데이터를 주고받을 때 논리적인 연결을 하지 않는 방식
→ 당연하게도 오류 제어나 흐름 제어 못 함
→ ACK 신호 같은 것도 없음. - Connection-Oriented (TCP)
: 프로그램 간 데이터를 주고받을 때 논리적인 연결을 설정한 후 통신하는 방식
→ 연결 설정 및 연결 해제를 한다.
→ 오류 제어나 흐름 제어 가능
◆ Reliable vs Unreliable
- Reliable (TCP)
연결 설정 및 해제를 하는 이유는 결국 신뢰 가능하도록 하는 것이다.
→ 그러면 프로그램 입장에선 신경쓸 게 없다. TCP가 알아서 에러 검출 복구 해주겠지~ - Unreliable (UDP)
통신이 신뢰 불가능하다.
→ 오류 제어나 흐름 제어가 필요 없는 서비스에 사용하거나, 앱 단에서 알아서 해결하도록 함.플컨, 에컨 없는 서비스에 쓰거나, 앱이 알아서 해결하도록 함
ex) 트위치 등
◆ 2계층에서 에러 검출 및 복구를 하는데, 왜 굳이 4계층에서도 하는가?
- L2가 담당하는 에러는 L1의 에러이다. 두 노드 사이 통신할 때 발생하는 물리적 에러 검출 및 복구를 했다.
- 그런데 L3에서 또 에러가 발생할 확률이 존재한다.
- CSMA에서도 봤듯이, L3는 Best Effort 방식, 즉 최선을 다해 반복하지만 결국 안되면 버리는 방식으로 동작하기 때문이다.
- 또는 L3 라우터에서 sw버그가 발생하거나, 순서가 바뀌거나, 트래픽이 몰려서 버려질 수도 있다.
따라서 L4 입장에서는 하위 레이어들을 신뢰할 수 없으므로,
이 과정에서 있을 수 있는 에러를 L4의 peer-to-peer의 관점에서 검출하고 복구하도록 한다.
◆ UDP는 에러 검출 및 복구를 안한다는데, 그럼 왜 쓰냐?
UDP는 에러 검출 및 복구를 하지 않는다.
그럼에도 젤 중요한 L4의 기능이 있는데, 프로세스를 식별하는 것이다. 포트 번호가 필요하다는 의미.
기능적으로 에러 검출 및 복구는 안하더라도 포트 번호가 source/dest process에 들어가있는 UDP 정보는 필요하다!!
◆ TCP의 에러 검출 및 복구 동작 (feat.TCP 헤더 필드)
TCP 헤더 필드에 포함된 Seqeunce number과 Acknowledgment number을 사용해 에러를 검출하고 복구한다.
ㆍSequence number
내가 보내는 세그먼트마다 번호를 붙인다.
=> 데이터 스트림의 순서 확인 및 수신 확인의 기능을 함.
ㆍAcknowledgment number
바이트 번호 x를 잘 수신했으면, Acknowledgment number 필드에다 x+1번을 넣어서 보냄 (확인 응답과 데이터는 piggyback 가능)
ex) ack 넘버 - seq 넘버 예시
클라가 서버에게 메세지를 보내는 상황.
클라는 서버에게 보낼 메세지 seq 넘버에다가 보내는 메시지의 첫번째 바이트 번호를 보낸다. "501번부터 보낼거야~"
서버는 타이머 후에 받은 메세지에 대한 응답을 한다.(원래 보낼 때마다 응답했는데, 배유정처럼 너무 시끄러워서 타이머제도로 바뀜)
이때 ack 넘버에다가 다음에 받아야할 메시지의 첫번째 바이트 번호를 넣는다. "나 700번까지 잘 받았으니, 이제 701번 내놔~"
만약 내가 Ack 넘버에 적은 숫자가 아닌 다른 숫자부터 시작하는 메세지가 왔으면, 일단 버퍼에 쌓아둠.
그리고 다음 응답시에 나 아직 이거 못 받았어! 하는 의미로, 받았어야할 Ack 넘버 넣어서 보냄. (재전송 요청)
그걸 보고 클라는 다시 자료를 주고, 서버가 잘 받았으면 다음에 받아야할 바이트 넘버로 답장함.
ex) acknowledgment lost시 resending
클라가 보낸 거 700번까지 잘 받고, 잘 받았다고 701번 Ack 보냈어. 그런데 뜬금없이 얘가 501번부터보내네?
그러면 야 아니야, 나 700까진 잘 받았어. 너 이제 701 주면 돼! 라는 의미로 다시 Ack를 보내줌.
Fast Retransmission
"야 에러가 났다고 알려줬으면 좀 빨리 보내야 할거 아니야!!!!"
같은 ACK("301 안왔다고!!") 를 3번 받으면, 타이머가 끝날때까지 안 기다리고 바로 보내도록 하는 거.
원래 두번째 타이머 시작하고, 끝나면 못 보낸거 보낼텐데, 계속 달라하니까 바로 주는 거. 조금 더 빨라짐
ㆍChecksum => 오류 제어
UDP와 같은 그 쳌썸
※ 컨트롤 파트 6개 살펴보기~
URG : 이거 긴급한 데이터야!!!!
ACK : ㅇㅋㅇㅋ. 확인
PSH : 지금 데이터 보낼거야 밑에거 전부 다 데이터야
RST : 연결 리셋!
SYN : 연결 요청!
FIN : 연결 종료!
< 연결 단계 >클라 : S 켜서 연결 요청(나 보내도 돼?)
서버 : A 켜서 연결 수락(ㅇㅋ 보내) + S 켜서 연결 요청(나도 보내도 돼?)
클라 : A 켜서 연결 수락(ㅇㅋ 너도 보내)
< 연결 해제 단계 >
클라 : F 켜서 연결 종료 요청(나 이제 그만 보내도 되지?)
서버 : A 켜서 종료 확인(ㅇㅋ 그만 보내) + F 켜서 연결 종료 요청(나도 그만 보낼게?)
클라 : A 켜서 종료 확인(ㅇㅋ 너도 그만 보내)
◆ TCP의 흐름 제어 동작 - TCP 헤더 필드
TCP 헤더에 있는 Window Size 필드를 통해서 흐름을 제어한다.
ㆍWindow Size => 흐름 제어
rwnd 란 수신자 윈도우 사이즈를 의미함.
① 클라: 나 연결해도 돼? 100 다음부터 보낼게
② 서버: ㅇㅋ연결해. 101부터 보내. 나도 해도돼? 1000 다음부터 보낼게. 나 윈도우 사이즈 800이야.
③ 클라: ㅇㅋ연결해. 1001부터 보내고. 내 윈도우 사이즈는 2000이야. 근데 나도 똑같이 너랑 800으로 잡을게
④ 클라: 나 101부터 보냈어. 200바이트 보냄!
⑤ 서버: 잘 받았어. 근데 아직 위로 못 올리고, 버퍼에 가지고 있어서 나 윈도우 사이즈 줄었어. 600이야.
⑥ 클라: 알았어 나도 600으로 조정할게. 잘 받았다니 101~300은 지우고, 이제 301부터 보낼게. 300바이트 보냄!
⑦ 서버: 잘 받았어. 601부터 보내면 돼. 근데 나 아직 100바이트밖에 위로 못 올려서 지금 윈도우 400 됐어. (800-200-300+100)
⑧ 서버: 아 나 200만큼 더 위로 올렸어. 이제 나 윈도우 600이야.
.
.
.
이런 식!
◆ TCP의 혼잡 제어
그림에서 클라가 서버에게 보낼 때,
상대방의 수신 버퍼 사이즈만큼 채우기 위해 노력은 할 것이나, 만약 상대방의 수신 버퍼가 크다고 하더라도, 내가 보낼 때 제한을 둘거야. – 라는 컨셉이 congestion window. (cwnd)
왜냐면, 상대가 바쁜 게 아니라, 네트워크가 바빠서 드랍될 수 있기 때문에 조심해서 보내자는 의미이다.
특정 선으로 트래픽이 몰리거나 하면 재수없게 버려지는 거니까.
기본적으로 TCP는 slow start한다. 처음에는 일단 조금만 보내보고, 조금씩 보내는 양을 늘린다는 뜻.
4개만큼 보냈는데, 상대가 잘 받았대! 그러면.. 살짝 제한 풀어. 5개 보내볼까?
상대가 잘 받았대!!!! 그러면.. 좀 더 풀어! 6개 보내볼까?
.
.
.
이러다가 결국, 상대방의 rwnd 만큼 조건 없이 보낼 수 있게 된다.