Flow Control / Close

Eden.Yang·2023년 10월 30일
0

Computer Network

목록 보기
17/25

리시버 버퍼의 오버플로우를 막는 것이 플로우 컨트롤

위에서 남아있는 리시버 버퍼의 사이즈를 알려주면 센더에서는 해당 윈도우의 사이즈를 맞춰준다.

rwnd가 sender의 window size가 된다.

타이니 그램 : 패킷을 보낼 때 메시지가 있으면 TCP해더, IP해더가 붙고 layer2에서도 뭔가가 붙는다. 이렇게 캡슐화가 발생. 실제 전달하는 메시지는 그런데 그런 헤더들이 아니라 메시지. 그렇기에 메시지를 제외하고는 overhead라는 말씀. 그래서 가능하면 message부분을 크게 보내는게 network입장에서는 효율이 좋다고 하겠다. 그러니까 타이니 그램은 메시지가 너무 작은 경우를 말한다.

41바이트는 40 해더(TCP 20 + IP 20) + 1 데이터라는 것

그럼 그냥 메시지를 무작정 모아? 키보드 입력 이후 화면에 출력되는건 로컬에서 발생하는 게 아니라 서버에 갔다 오는거임. 그래서 메시지를 모아서 보내면 사용자가 입력을 해도 반응이 없게 보여서 답답하다는 것. 그래서 두가지 문제를 동시에 해결해야 함.

그래서 어떻게 하면 되는가?

Nagle's algorithm

처음 byte는 받아서 타이니 그램으로 그냥 넣는다. 그리고 나서는 첫 바이트의 액이 오기 전까지는 버퍼에 메시지를 쌓는다. 혹은 리스판스가 늦을 경우 버퍼링을 한 양이 윈도우 사이즈의 반이 찾거나 세그먼트의 멕시멈이 됐으면 그냥 보내겠다는 것.

하지만 요즘은 많은 경우window environment쪽에서 많이 한다. 클릭 클릭 여기에서는 내글을 disable하는 게 좋다.

데이터를 보내기 전에 미리 핸드쉐이킹을 해놓고

왜 2를 하면 안돼? 꼭 3를 해야 하나?

2way 핸드 쉐이킹을 하면 딜레이가 가변적이고 메시지 로스나 재전송이 일어나고 메시지 도착 순서가 어긋날 수 있고 다른 편 상황을 알 수 없다.

두번쨰 그림
애크가 오기 전에 타임아웃으로 재 전송을 하면 다 닫은 다음에 도착? 그러면 서버에서는 클라이언트에서 리퀴스트가 왔으니까 또 액을 준다. 그런데 이 액이 커넥션 리퀘스트를 안 한 상태이니 프로토콜을 보니 이그노어해버림. 그러면 half open상황이 되어버림. 서버입장에서는 채널이 열려 있다(리소스를 사용하고 있다). TCP에서는 그래서 half open, half close같은 것들이 있다. half open은 비정상이지만 half closed는 가능한 상황.

세번째 그림
액을 받아서 데이터를 보내기 시작. 그러다가 커넥션이 끝겼는데 핸드 쉐이킹과 데이터 둘다 커넥션이 끊긴 이후 도착을 하면 서버 입장에서는 액을 주면서 채널을 열고 그다음 데이터니까 저장을 하는 등의 액션을 취한다. 그런데 기존에 받은 데이터랑 똑같은데 액션을 취하니까 문제가 되는 것. 2 way handshaking에선 이런 문제를 막을 방법이 없다.

3쉐이킹은 상호간의 독립적인 seq넘버를 전해준다. 신과 엑 플랙이 둘다 일이면 커넥션 리퀘스트가 억셉트 된 것. 2웨이에서는 저 단계가 없다. 뭔가 안 맞으면 reset을 통해 해당 커넥션을 끊음.

두번째 그림
커넥션 리퀘스트가 재전송되고 있는 상황. 커넥션이 위의 2way의 세번쨰 그림과 비교. 서버 쪽에서는 이스테블리시 먼트가 끝나지 않음. 백이 와야 하는데 상호간의 seq와 ack이 달라서 해당 3번째 데이터를 버리고 안 받음. 그래서 리셋을 시켜버림.

동시에 서로 끝어도 정상적으로 동작함

일반적으로 클라이언트에서 먼저 닫는다. 함수를 부르든지 셧다운을 하던지..그러면 FIN flag 이 1이 되고 이에 대해 ack을 서버가 주고 x+1로 데이터는 없지만 준다. 그러면 클라이언트~서버 통로는 막힌 것. 그러나 여전히 서버에서 클라이언트 쪽은 열려 있는 것임. 프로그램 시에는 양방향이 다 끊길 수도 있음. seq넘버가 핀을 1로 보내면 ack이 TIME_WAIT상태가 됐을 것. 일반적으론 4개를 갖고 하지만 가끔은 2,3번이 동시에 될 수도 있음. 액을 주면서 동시에 끊을 수도 있음. 그러면 패킷 3개로도 가능

네모 : state

트랜지션 될 땐 /를 사용
event / action(Listen / -)

red line : 일반적으로 클라이언트 동작 링크.
blue line : 일반적으로 서버 동작 링크

커넥트를 부르면서 syn을 보낸다. 그러면 클라이언트는 synsent state로 간다. 거기서 보낸 syn packet이 server에 도착. 그래서 syn+ack으로 답한다. 자신은 syn received상태가 된다. syn+ack이 클라이언트에 도착하면 ack으로 응답한다. 그리고 이 ack이 서버에 도착. 그러면 connection establishment. 그러면 둘 다 데이터 주고받을 수 있는 상태. 다 끝났다. 그러면 이제 커넥션을 닫아야. 일반적으로 client가 닫음. 그러면 close/FIN 이 된다. fin wait1상태가 된다. 그러면 서버에는 fin/ack이 도착한다. 그러면 서버는 ack을 주고 close wait상태가 된다. 이 ack이 클라이언트 도착하면 fin wait 2 상태가 된다. 서버도 다 보냈으면 close를 한다. 그러면 last ack상태가 된다. fin packet이 도착하면 클라이언트 쪽에서 액을 하고 타임 웨잇 상태. 그리고 액이 서버에 가면 서버는 닫고 타임아웃이 되면 클라이언트도 닫는다.

ctrl C는 죽이는 것 ctrl z도 외형상으론 죽는 것 같지만 process state를 보면 살아있다. z는 프로세스를 좀비상태로 만들어서 프로세스를 차지 하고 있는 것. 그런데 서버를 죽이면 먼저 클로즈 한얘가 빨간 라인을 타게 된다. 문제가 없긴 하지만 서버가 time wait상태를 2분간 만나는데 터미널에선 종료된 것 처럼 보이지만 사실은 ps처서 보면 서버 프로세스가 타임웨잇에 있어서 살아있다.

1번째 : 2MSL(Maximum Segment Lifetime) wait
2번째 : different port
사용자가 사용하고 있찌 않은 포트넘버를 가진다. 그런데 서버를 죽이고 리컴파일을 하면 에러가 뜬다. 왜냐? 서버 포트넘버는 OS가 어사인해주기 때문이다. 그런데 현재는 서버가 타임 웨잇이니 2분간 살아있다. 다시 말해 그 포트넘버를 사용하고 있다는 것. 또 사용하려고 하니까 에러가 나는 것. 소위말하는 바인드 에러이다. 서버를 먼저 죽일 땐 다시 돌렸을 때 에러가 나면 바인드에러인 걸 알아야 한다.

profile
손끝에서 땅끝으로, 골방에서 열방으로

0개의 댓글