
위 그림을 다시 한번 언급한다.
연결 종료 시 process의 time-wait가 필요한 이유 중 하나를 설명한다,
예를 들어 client1이 3456 포트에서 연결을 종료하자마자
다시 연결 요청을 보내었다고 가정한다.
만약 time-wait이 존재하지 않으면 시스템은 다시 한번 3456 포트를
할당해 줄 가능성이 있다.
파란선 위의 연결에서 보냈다가 잘못된 라우팅으로 인해
파란선 아래 연결 시점에 도착했다고 생각해보면
서버의 입장에선 이 패킷이 이전 연결인지 이후 연결인지
3456포트 같은 ip에서 왔기에 구분할 방법이 없다.
패킷이 네트워크에 존재 가능한 시간동안 port를 반납하지 않으면 된다.
IP header에 모든 패킷은 timer를 달고 일정 시간이 지나고
네트워크 상에 존재하면 라우터가 버려준다.
이것은 잘못된 라우팅으로 인한 무한loop가 쌓여서 트래픽을 먹는 것을 방지한다.
만약 서버가 FIN Activate라면

연결 후에 같은 port로 서버를 켜려면 bind error가 난다.
이유는 server가 time-wait에 들어가 백그라운드에서 9090port를
점유하고 있기 때문이다.

서버는 항상 같은 port에서 대기하여야 하기 때문에 옵션을 주어
time-wait 진입을 막아둘 수 있다.
TCP는 신뢰성 보장을 위한 방식 중 ACK 방식을 사용한다.
이것은 Stop & Wait 방식으로 매우 비효율 적이다.
이러한 비효율성을 해결하기 위해 TCP는 한번에 하나씩 보내는 것이 아니라
여러개를 보내게 된다.
그렇다면 여러개의 기준은 무엇일까
이것은 항상 가변적이다.
수신 측의 receiver buffer 가용범위에 따라 다르다는 것이다.
그렇다면 얼마나 보낼 수 있는지 어떻게 알 수 있을까

이전에 언급한 TCP 헤더를 보면 Window라는 16bit 공간이 할당되어 있는 것을 볼 수 있다.
이것이 받는 측의 수용 가능 범위를 알려주는 부분이다.
다시말해, ACK을 보낼 때 내가 얼마나 받을 수 있는 지도 실어서 보낸다는 것이다.

이전에 보았던 사진이다.
당시에는 rwnd의 부분을 이야기 하지 않았지만, rwnd는 초기에 버퍼가 얼마만큼 할당되었는 지 알려주는 부분이다.

sender를 보자
201~300은 보낼 수 있는 윈도우 사이즈가 된다.
즉 받는 측에서 100만큼 받을 수 있다고 알려준 것이다.
왼쪽에 색칠된 부분은 이미 보낸 부분이다.
손실에 대한 재전송을 위해 남아 있다.(ACK 받으면 제거)
261~300은 아직 보내지 않은, 보낼 수 있는 byte size이다.
만약 ACK 261을 받고 가용 숫자가 100이 왔다면
201~260는 버리고 261~360이 새로운 윈도우가 된다.
이렇게 윈도우가 오른쪽으로 흘러가는 것 처럼 보인다 하여 sliding window 방식으로 부른다.

receiver는 받을 때마다 그만큼 window size를 줄이고
application이 소모할 때 마다 window size를 늘려가며 sliding 한다.
이것이 TCP의 Flow Control이다.
핵심은 상대가 받을 수 있는 만큼만 보내는 것이다.

이번 실습에서는 다중 클라이언트를 처리하는 서버를 구현한다.
다중 클라이언트를 처리하기 위해서는 멀티 프로세스 또는 멀티 쓰레드 기반으로 구현해야 하며 리눅스의 fork함수를 이용하여 멀티 프로세스 구현을 한다.
먼저 프로세스란 직관적인 해석으로는 실행 중인 프로그램이다.

운영체제는 프로세스 마다 ID를 할당하며 이것은 pid라고 부른다.

기존 실행 프로세스가 fork()라는 함수를 호출하게 되면
따라서 if(pid == 0) 과 같은 조건문을 이용하여
부모 프로세스와 자식 프로세스의 행동을 제어할 수 있다.
좀비 프로세스는 실행이 완료되었음에도 소멸되지 않고 남아있는 프로세스이다.
메모리상에 프로세스가 사용한 리소스가 남아있다는 의미이다.
발생 원인은 자식 프로세스가 종료하면서 반환하는 상태 값이
부모 프로세스에게 전달되지 않으면 발생한다.

운영체제가 프로세스에게 전달하는 일종의 메시지를 시그널이라 한다.

특정 상황에서 운영체제로부터 프로세스가 시그널을 받기 위해서는 해당상황에 대한 등록과정이 필요하다.


핵심은 서버가 클라이언트와의 연결마다 프로세스를 생성하여
서비스를 제공해주는 것이다.

클라이언트와 연결이 되면 fork() 호출하여
자식프로세스가 서비스하도록 한다.

프로세스가 복제되는 경우 소켓자체가 복제되는 것이 아닌
FD가 복제되는 것임.
따라서 하나의 소켓을 가리키는 모든 FD가 종료되어야 소켓이 소멸된다.