Application layer는 우리가 실제로 짤 수 있는 network program이다.
Internet protocol 5계층(application, tansport, network, link, physical layer)
Transport layer는 network edge에 있다.
end-to-end로 application message들을 어떻게 잘 보낼 수 있을까?를 처리한다.
transport layer data를 destination에서 decapsulation하기 때문에 end-to-end이다.
각각의 layer마다 packet을 부르는 이름이 다르다.
application에서 message를 transport를 보내주면, 작은 message와 큰 message가 있을 것이다.
transport layer에서는 자기가 관리할 수 있을만큼 자른다.
그래서 tranport layer에서는 자기가 관리할 수 있는 data의 단위를 segment
라고 한다.
자른 segment들을 network layer에 보낸다.
나중에 network layer에서는 잘라진 packet들은 이제 더이상 '순서'라는 것이 없어진다.
그래서 decapsulation할 때, application layer에서는 순서를 모르기 때문에
packet을 잘랐던 transport layer에서 다시 reassembling하여 application layer로 보내줘야 한다.
Transport layer VS Network layer
:
Network layer는 host들 간의 logical한 communication을 만들기 위해서 network core를 사용한다.
= IP 단위로 host-to-host로 전달한다.
transport layer는 process 간의 logical한 communication을 만든다.
= host 안의 여러 application process들 중에서 특정한 application process에 전달한다.
transport, network, link, pyhsical layer는 모두 OS에 들어있다.
여러 개가 아니라 하나의 service가 도는 것이다.
여러 application에서는 이 하나의 service를 사용해야 하기 때문에 system call을 통해 사용한다.
transport, network, link, pyhsical layer 가 하나의 service인데,
요청하는 application이 많으면 어떻게 해야 하는가? ➡️ multiplexing, demultiplexing (이 data는 어떤 application꺼인지?)
Multiplexing (Mux)
:
Demultiplexing (Demux)
:
identifier 정리
:
1. 어떤 host에서 보낸것인가? source IP address
2. 그 host의 어떤 application process에서 보낸 것인가? source port number
3. host는 어떤 destination으로 보낸 것인가? destination IP addres
4. destination의 어떤 application process으로 보낸 것인가? destination port number
이렇게 host들은 적절한 application에서 받아들이기 위해 source IP address, source port number, destination IP address, destination port number를 갖고 Multiplexing을 사용한다.
만약 destination의 port number가 같으면, 어떻게 구분하는지?
source IP address와 source port number를 보면 된다.
UDP socket에다가 destination IP address, port number를 넣어야 한다.
connection-oriented reliable transport layer protocol
, reliable
, in-order delivery
:
application에서 주는 message를 transport에서 자기가 관리할 수 있는 만큼 segment로 자른다고 했다.
TCP는 자른 segment들이 모두 오기를 기다렸다가 reassembling하여 보내준다.
추가적으로 flow control
, congestion control
, connection setup
이 필요하다.
source에서 destination까지 data를 보내기 전에,
circuit switching을 했던 것처럼
source의 TCP에서 destination의 TCP까지 end-to-end connection을 만들어놓는다.
그래서 TCP는 connection-oriented service라고 한다.
따라서 통신이 끝나면, connection을 끝내주는 작업도 필요하다.
이러한 작업들을 수행하기 위해 header에 정보들을 붙여야 한다.
따라서 TCP는 자체의 overhead가 커서 시간이 오래 걸린다.
connection-oriented = TCP demux
:
transport layer에서 어떤 application으로 줄 것인지? = 어떤 socket에 줄 것인지?
TCP는 연결을 한 번 해놓으면, 그 이후에는 data를 계속 주고 받을 수 있다.
TCP 연결을 하면, destination의 application과 통신할 수 있는 전용의 process가 생긴다.
TCP 연결수만큼 process가 생긴다.
destination(server)에서 data를 받았는데, 이것을 어느 application process에 보낼 것인가?
server의 port number는 같기 때문에, 어느 process에 보내야 할지는 모른다.
그렇기 때문에 해당 source process의 port number 뿐만 아니라 IP address까지 필요하다.
TCP demux는 source IP address, source port number, dest IP address, dest port number 4개가 필요하다.
connection-less transport layer protocol
, less reliable
:
no-frills extension of "best-effor" IP
군더더기 없이 최선을 다한다. 하지만 책임은 지지 않는다.
군더더기가 없다 = data를 받는 대로 application으로 올린다. 빠르다. ➡️ time sensitive service에 사용된다.
Connectionless == UDP demux
process에서 9157이라는 자신의 port를 만듦.
destination은 6428
UDP demux는 source port number와 destination port number, 2개만 있으면 된다.
datagram을 network layer에서 packet을 부르는 용어인데, UDP는 tranport layer에 있다.
왜 그러면 datagram이라고 부르는가?
UDP는 transport layer에서 하는 일이 거의 없다는 의미이다.
server와 client 사이의 handshaking이 없이 host의 application에서 요청하면,
바로바로 해당하는 destination의 port number로 연결된다.
따라서 streaming multimedia application에 유리하다.
DNS에서 UDP를 사용한다.
UDP를 사용하여 어떻게 reliable한 transfer를 하는가?
UDP segment header
: UDP에서 checksum을 계산하여 error detection을 한다.
하지만 UDP는 less reliable data transfer기 때문에 data integrity를 보장하지 않는다.
따라서 우리는 reliable data transfer가 필요하다.
실제로 channel은 다양한 이유로 인해서 unreliable한 특성을 갖고 있다.
즉, data는 channel(router, switch, 등)을 통과할 때, 문제가 발생할 수 있다.
application에서 하위 계층으로 data를 보내는 것은
하위 계층에서 제공하고 있는 함수를 call하여 data를 넣어주는 것이다.
예를 들어, application layer에서 transport layer의 rdt_send() 함수에 data를 넣어서 data를 보낸다.
이때 sender는 packet을 unreliable channel을 통해 receiver에게 보낸다.
receiver는 packet을 받고, deliever_data()를 통해서 application layer로 data를 보낸다.
여기서, unreliable channel에서 어떤 일이 발생하는지? 어떤 일을 해야하는지?를 배울 것이다.
unreliable data transfer
: 문제가 있으면 버리고, 문제가 없으면 바로 보내줌
reliable data transfer
: 문제가 있으면, transport layer에서 해당 문제를 다 해결할 때까지 data를 application에 보내주지 않음.
FSM(Finite State Machine = State Transition Diagram)
FSM은 state가 바뀜으로 인해서 어떠한 event/action이 있는지 정의하기 위해 사용한다.
sequential한 program에는 FSM을 사용하지 않아도 되는데,
다양한 event가 발생하는 program에서는 FSM이 필요하다.
그런데 왜 FSM이 나오는가?
packet을 주고 받을 때,
packet을 받았을 때, 어떤 packet을 받았는가에 따라서 state를 다르게 정의하여 reliable data transfer를 보장할 것이다.
rdt1.0
:rdt2.0
:
만약 channel에 bit error가 있다면? 즉, 중간에 오는 packet이 깨진다면?
checksum으로 확인할 수 있다.
하지만 checksum으로 확인까지만 하는 것은 UDP인데,
reliable data transfer이기 때문에 error가 발생한다면, 어떻게 recovery를 할 것인가?
sender 입장에서는 자신의 packet이 잘 갔는지 안 갔는지 확인하기 위해
packet을 보내고, 각각의 packet에 대한 response 받아야 한다.
그 response는 receiver에서 보내는데,
response는 ACKs(Acknowledgement), NAKs(Negative Acknowledgements)이다.
만약에 receiver가 checksum하여 error가 발생한 것을 알았다면? NAK을 response한다.
만약 sender가 NAK을 받으면, retransmission한다.
정리하자면,
rdt1.0에서 error detection(checksum), feedback(ACKs, NAKs)이 추가되어 state가 더 많아졌다.
application에서 transport에서 무엇을 하고 있는지 모르게(transparent하게) 하여 tranport layer를 설계함.
하지만 rdt2.0은 치명적인 단점이 있다!
만약 ACK/NAK가 corrupted된다면?
rdt2.0에서도 channel 자체가 unreliable channel이기 때문에
receiver에서 보낸 response인 ACK, NAK 자체도 unreliable channel로 전송된다.
따라서 ACK, NAK조차도 unreliable하다.
➡️ duplicate msg를 어떻게 처리할 수 있을까? ACK, NAK가 깨졌는지 어떻게 확인할 수 있을까?
지금까지는 매번 packet마다 independent했는데,
보내는 packet에 대해 고유한 sequence number를 붙여서 identification한다.
receiver쪽에서는 잘 수신한 sequence number를 처리했다는 정보를 buffer에 저장하고 있다.
만약 똑같은 sequence number packet이 들어오면, duplicate data이기 때문에 discard한다.
➡️ 이러한 protocol 형식을 Stop and Wait
라고 한다.
sender가 한 packet씩 보낸다.
receiver가 response하기 전까지 wait했다가 완벽히 처리되었을 때, 그 다음 packet을 처리한다.
Sender, Receiver의 형광펜, 파란색 부분 중요함.
Sender
:Receiver
:그런데 packet의 sequence number를 0, 1만 사용해도 충분한가?
충분하다.
stop and wait로 한 packet씩 기다리기 때문에
이번 packet이 0번이면, 그 이전의 packet을 받아도 discard하거나 ACK를 보내줘서 대처할 수 있다.
rdt2.2
:rdt3.0
:
가정이 하나 더 들어간다.
지금까지는 bit error만 고려했었는데, loss도 발생한다고 가정.
bit error만 있으면 아무리 심각하게 깨져도 도착은 해서 처리를 할 수 있다.
하지만 loss는 심각하다.
sender는 보냈는데 receiver는 아무것도 받지 않아 feedback 자체를 받을 수 없다.
그래서 Timer
를 써서 loss를 극복할 수 있다.
Timeout이 되기 전에 feedback이 오면, 이전처럼 처리.
만약 loss가 생긴다면 timeout이 되어 interrupt가 발생.
Timeout이 되면, receiver는 당연히 아무것도 받지 않았기 때문에 처리할게 없다.
sender는 재전송해야 한다.
Utilization
:pipelining
:
packet 1개를 보내고나서 stop and wait하는 것이 아니라,
우선 packet들을 계속해서 보내고 나서 그 후에 처리를 해보자.
그래서 utilization을 좋게(packet들을 더 많이, 빨리 보낼 수 있도록) 해보자.
Pipielined protocol
:
pipelining 기술에는 크게 두가지가 있다.
Go-back-N
:
Sender
:
cumulative ack : 3번에 대한 ack를 받았다 = 이미 1, 2, 3번은 잘 받았으니 4번 packet으로 sliding하고, timer restart.
Receiver
:
GBN in action
:
Selective Repeat
:
Sender, Receiver windows
:
Selective repeat in action
:
Selective repeat dilemma
:
receiver 입장에서는 (a), (b) 모두 똑같은 sequence number를 받지만,
서로 다른 data이다.
(a)에서는 제대로된 data를 받지만
(b)에서는 receiver가 처음에 보내는 ack0, 1 2가 모두 loss되었는데 receiver는 이를 모른다.
sender는 ack가 오지 않았기 때문에 처음 보낸 pkt0, 1 2를 재전송한다.
이때, receiver는 그 pkt들이 처음 pkt 0, 1, 2라 생각하지 않고 pkt 4(0), 5(1), 6(2)라고 생각하게 된다.
➡️ 이에 대한 해결법으로는 seq number를 충분히 길게 하면 된다.
TCP는 표준이 여러개이다.
TCP는 point-to-point(= one-to-one)
이다. (1 : N이 아니다)
reliable, in-order byte steam이다.
pipelined
방식 사용.
congestion control, flow control을 한다.
하나의 TCP connection으로 full duplex data가 가능하다.
:
connection-oriented
:
UDP는 data가 생기면 destination으로 바로 보내고, receiver는 받았을 때 checksum error가 없으면 바로 application layer로 올려줌
하지만 TCP는 data를 보내기 전에 TCP connection을 수립하고 나서 data를 보내기 시작한다.
(비교를 위한) UDP segment structure
:TCP segment structure
:source port #, dest port #
: sequence #, acknowledge #
: head len
:acknowledge #
: U
: Urgent flag (1이면, 그 data에서 어디까지를 urgent하게 보낼것인가? -> 많이 쓰이지 않음)A
: 1이면, "data에 대한 Ack packet이다"라는 의미.P
: PUSH data nowR(Reset), S(Syn), F(Fin)
:checksum
:Loop back
: 보낸 것을 그대로 돌려줌. (echo)TCP timeout value는 어떻게 설정하는가?
:
TCP는 pipeline을 사용하는데, 기본적으로 GBN 방식을 사용한다. = Timer 1개만 사용한다.
network는 상황에 따라 RTT가 계속해서 다르기 때문에 timer를 고정된 값으로 설정하면 안된다.
따라서 RTT에 적합한 time을 setting하는 것이 중요하다.
따라서 지속적으로 RTT값을 monitoring하여 exponential weighted moving average를 통해
현재의 RTT 기대값인 EstimatedRTT에 조금 더 margin을 둬서time을 설정해야 한다.
timeout interval
: EstimatedRTT + "safety margin"
"safety margin" = (typically, ))
➡️ timer값이 너무 크거나 너무 작은 것을 방지하기 위해
과거부터 현재까지 RTT 변화추이를 잘 따라갈 수 있는 EstimatedRTT를 구할 수 있고,
그 값을 기반으로 safety margin을 둬서 최종적으로 TimeoutInterval을 구할 수 있다.
➡️ 하지만 위 방법이 최선은 아니고, 이 외에도 다양한 TimeoutInterval setting 방법(논문들)이 있다..
reliable data transfer는 TCP의 가장 핵심적인 기능 중 하나이다.
duplicate acks, flow control, congestion control을 무시하고 simplified TCP sender의 입장을 고려해보자.
TCP sender events
:
Lost ACK scenario
:
premature timeout
:
cumulative ACK
:
TCP fast retransmit
:Flow Control
: 2-way handshake
:
가장 기본적인 connection 방법.
항상 client가 server에게 먼저 request한다.
하지만 2-way handshake가 문제가 되는 상황이 있다.
2-way handshake failure scenarios :
Client가 establish되기 전에
Server에서 establish가 먼저 되기 때문에 문제가 발생하는 것임.
그래서 TCP에서는 3-way handshake를 사용함
3-way handshake
: Congestion control과 Flow control은 완전히 다르다.
Flow control
은 network 상황과는 관계가 없다.Congestion control
은 sender가 data를 빠르게 보내서 network core에 많은 data들이 loss되거나 delay되는 것을 해결하기 위한 문제이다.packet이 loss되거나 delay되는 것이 congestion 때문이다.
congestion되는 것은 sender에서 책임져야 한다.
congestion 문제는 NP problem이어서
논리적인 방법, 물리적인 방법(Link speedup)이 연구되어지고 있다.
Congestion이 발생했는지 어떻게 아는가?
manifestations(조짐, 징후)가 있다.
timeout이 빈번히 발생
:delay가 길어짐
:Congestion 발생 scenario :
Packet loss가 되면, timeout, 재전송
원래 data가 빨라서 생기는 문제도 있지만
재전송되는 data도 network로 같이 들어가는 것도 문제임.
data가 보내지고 있는 중에 timeout이 걸려서 재전송 된다면
original data와 retransmission data들은 network에 함께 존재
➡️ 계속해서 악화되는 congestion
throughput R/2를 넘어서는 순간 꽉 막혀버린다..
TCP의 기본 철학
그러면 TCP에서는 congestion을 어떻게 control할 것인가?
AIMD(Additive Increase Multiplicative Decrease)
Slow Start
AIMD(Additive Increase Multiplicative Decrease)
Slow Start
:timeout이 발생한 경우(가장 심각한 경우)
:3 duplicate ACK가 발생한 경우
:나의 cwnd가 작을 때,
다른 client의 cwnd는 커서
불공평한 상황이 있지 않나?
➡️ 아니다.
시간이 지나면서 equal bandwidth share로 수렴하기 때문에 fair하다.
congestion이 발생하면, 나만 천천히 보내는 것이 아니라 다른 client들도 상황을 인지하고 천천히 보내고 있을 것이다.
➡️ 또한 TCP는 OS 하나의 task이고
TCP에서는 이러한 일을 계속해서 하고 있기 때문에 overhead가 꽤 큼
한 application에서 TCP를 여러개 만들 수 있음
만약 3개 만들었다면, 3개는 별도로 연결 수립이 이루어짐
그러면 여기서의 congestion control은 한 연결 당 하나씩 TCP congestion이 이루어짐.
앞서 한 TCP 연결마다 fair하다고 했는데,
이것을 역이용하는 방법이 있다
➡️ application에서 조작하는 것.
한 computer에서 TCP를 parallel로 여러개 만듦.
link가 R이고 이미 서로 다른 9개의 TCP connection이 있다고 가정.
나도 새로운 application의 TCP를 넣으면 총 10개.
처리할 수 있는 rate는 각각 R/10이므로 fair함.
그런데 만약 내가 11개의 TCP 연결을 parallel하게 만든다면,
총 20개 중에 나의 TCP가 11개가 된다.
그러면 그 link의 (11/20)*R만큼의 rate를 제공받아서 절반 이상의 TCP rate를 제공받을 수 있다.
web server에 이러한 꼼수를 이용함.
원래는 web server에 TCP 1개를 연결하여 object를 순차적으로 1개씩 가져오는데,
object수만큼 parallel하게 TCP를 연결해서 한 TCP 당 한 object를 가져와서 매우 빠르게 받을 수 있다.
Congestion control은 sender가 data를 빠르게 보내서 network core에 많은 data들이 loss되거나 delay되는 것을 해결하기 위한 문제이다.
하지만 책임은 core가 아니라 edge에 있는 host의 transport layer의 TCP에서 졌었다.
network-assisted congestion control
:
또 다른 기술로 network layer에서 직접 congestion 문제를 해결하려는 기술이 있다.
IP header에 ToS (Type of Service)라는 field가 있다.
network router가 congestion이 일어났으면?
ToS field에 ECN bit에 congestion이 일어났다고 명시적으로(explicit) flag를 올려준다.
Destination에서는 TCP ACK segment 안에 ECN bit를 set하여 다시 보내준다.
➡️ 사실 거의 안쓰이는 알고리즘이다.