TCP와 IP는 헤더가 기본적으로 20byte

그림 b는 TCP 헤더를 확장한 것이며 왼쪽 상단의 1 => 0으로 수정
한 행에 4 byte(32 bit)이며 기본적으로 5행으로 분리된다.
row1 process to process를 위한 port번호의 pair가 저장
row2 packet의 sequence number가 저장된다.
row3 ack번호가 저장된다.
row4

헤더의 길이를 저장한다.
TCP 헤더는 20~60byte인데 어떻게 4bit(0~15)로 표현가능한 이유는 TCP 헤더는 항상 4byte 배수로 설계 되었기 때문에 실제 헤더길이의 4로 나눈 값을 보내어 간단하게 전송할 수 있게 된다.
예를 들어 헤더의 길이가 52byte라면 HLEN 필드에 13을 저장하여 보내고 받는 쪽에서 다시 4를 곱하여 사용하면 된다.


ACK 비트가 1일 경우 ACK field에 대한 유효성을 알려준다.
SYN, FIN은 후술할 3 way handshake에서 다룸
row5
checksum 필드는 아래 IP 헤더의 예시를 본다.

전송에러를 탐지하기 위한 용도이며 다 더한 후 보수값을 취한다.

segment는 전송데이터 까지 포함한 전체의 checksum을 보내고
datagram에서는 IP 헤더의 checksum을 보낸다.
frame에서는 tail 에서 검사한다.

TCP 헤더는 segment부분과 앞의 IP헤더쪽 까지 checksum을 하여 double-check를 해준다.
packet들을 16비트씩 쪼개어서 다 더하고 맨 왼쪽 비트에서 carry가 발생하면 가장 오른쪽 비트에 다시 더하는 end-around carry방식을 사용한다.
The use of the checksum in TCP is mandatory
In UDP, checksum is option

payload : 자신이 붙인 헤더를 제외한 데이터 영역
Frame 뒤에는 tail이 붙으며 오류검출에 대한 CRC 값이 있다.

클라이언트 - 서버 간 TCP 연결 과정을 나타낸 그림이다.
이렇게 SYN+SYN+ACK+ACK 순서로 이어지는 연결 성립 과정을
3-way handshake라고 부른다.
지난 글에서 circuit switching network와
packet switching network를 언급한 바 있다.
우리 인터넷은 packet swtiching 방식을 사용하고
이것은 connection less에 해당한다.
반면 circuit switching network는
connection oriented라고도 불린다.
우리 인터넷에서 쓰이는 TCP는 완전 연결을 보장한다고 하는데,
왜 packet swithcing network에 속할까
TCP의 connection oriented는 물리적 경로가 아닌
논리적 연결에 관해 이야기 하는 것이다.
바꿔 말하면 서버와 클라이언트 간에 연결 시 셋업을 하냐 안하냐의
차이를 나타내는 말일 뿐이다.
연결 셋업이 끝나면 양 측은 sender, receiver 버퍼 pair를 생성한다.
또 하나의 궁금증은 ACK에 대한 ACK는 어떻게 해결하냐는 것이다.
이것은 RTO 및 RTT의 개념에서 해결된다.
모든 패킷마다 timer를 걸고 일정 시간동안 응답이 오지 않으면
재전송 하는 방식으로 완전 연결을 보장한다.

이 그림은 3-way handshake의 소켓프로그래밍 관점에서 설명하는 그림이다.
먼저 클라이언트 측은 소켓을 생성하고 connect를 호출한다.
connect를 호출하는 것은 SYN 패킷을 보내는 것이다.
그 후 응답까지 block 한다.
서버 측은 소켓을 생성하고, 응답 소켓으로 바꾼 뒤
연결 요청에 대한 accept를 호출한다.
그 후 응답까지 block 한다.
클라이언트는 응답을 받은 다음 connect에 대한 return을 한다.
서버 또한 응답을 받은 뒤 accept에 대해 return한다.
일반 소켓에다가 SYN 패킷을 보내도 SYN+ACK 패킷을 생성하지 않는다.
따라서 서버는 listen을 통해 서버 소켓으로 바꾸는 과정이 꼭 필요하다.
프로그램의 관점에서도 서버가 먼저 실행이 되어야 통신을 할 수 있다.

실제로는 cumulative ACK 방식이기 때문에 사실 모든 패킷에 대한 응답을 할 필요 없이 2번의 수신에 대한 한번의 응답으로도 구현이 가능하다.
3-way handshake 방식의 통신 종료를 살펴본다.

클라이언트 측에서 FIN flag를 활성화 한채 FIN packet을 보낸다.
서버 측은 응답과 동시에 FIN 패킷을 보낸다.(FIN + ACK)
클라이언트 측은 응답을 보내고 연결을 종료한다.
FIN+FIN + ACK+ACK 패킷의 종료 과정 이것이
3-way handshake 연결 종료이다.

close 함수를 통해 FIN 패킷을 보낸다.

실제 코드를 보면 read가 0을 반환하기 전까지 write하는데
read는 FIN을 받을 시 0을 반환한다.
따라서 read의 무한 루프를 통해 FIN을 탐지하고 연결 종료가 시작된다.
종료 과정은 프로그램에 따라 4-way handshake로 이루어 질 수 있다.

read를 호출하면 block 하므로 양측이 동시에 read를 호출해 deadlock이 발생하는 것을 주의하여 구현해야 한다.

클라이언트는 연결을 종료하였지만 서버는 아직 보낼 정보가 남아있는 상태이다.
클라이언트는 FIN 패킷을 보내고 서버는 ACK를 보낸 후
Sending buffer를 제거한다.
서버는 데이터를 계속 보내고, 클라이언트는 응답만 하는 상태이다.
이후 서버도 FIN 패킷을 보내면 응답을 받고 최종 종료된다.
어플리케이션 관점에서 socket을 다루는 것이 파일과 동일하기에 살펴본다.

운영체제가 만든 파일에 부여하는 일종의 숫자
FD의 0,1,2은 이미 지정되어 있다.

open함수를 통해 지정된 경로에 있는 파일을 특정 모드로 열고
FD를 반환해 프로그램에서 사용한다.

write함수에 FD를 전달하여 파일에 데이터를 쓸 수 있다.

read함수에 FD를 전달하여 저장된 데이터를 읽을 수 있다.

소켓 생성 시 프로토콜을 지정해야 한다.
보편적으로는 IPv4 - TCP 프로토콜을 지정한다.


첫번째 매개변수

두번째 매개변수
TCP의 설명 중 데이터가 소멸되지 않는 것과 전송 순서는
어플리케이션의 입장에서만 맞는 말이다.
UDP의 설명 중 첫번째는 x


인터넷에서는 3가지의 주소가 필요하다.

port 번호는 한 PC내의 어플리케이션들에 부여되는 번호라고 생각하고 넘어간다.

IP주소와 PORT 번호를 sock에 매핑한다.



PC 마다 사용이 다르기에 정수값을 주고 받을 때는 Big Endian으로 통일

내 PC와 관계없이 network byte order로 전송하고
받은 다음에는 host byte order로 바꾸어야 함

IP주소가 문자열로 전달되기에 정수로 변환해야 한다.
inet_addr 함수를 쓰면 정수 및 빅엔디안으로 저장한다.

inet_aton 함수도 같은 기능을 가진다.
inet_ntoa는 반대 역할

클라이언트 코드에서는 서버의 PORT번호를 작성하고
전송때에는 시스템이 자동으로 사용하지 않는 포트번호를 클라이언트한테 지정해준다.