티스토리 뷰

TCP는 Transport layer(4 layer)의 프로토콜인데, 4 layer의 통신은 애플리케이션 프로세스들간의 논리적인 통신이라고 할 수 있다.


호스트의 TCP 소프트웨어간에 데이터를 교환하는 unit은 TCP segment라고 부름.

TCP segment는 TCP header와 TCP data(optional)로 구성되어 있다.


[TCP segment = TCP header + TCP data]


TCP header의 format은 다음과 같다.


port number

TCP나 UDP와 같은 transport layer에서 호스트에서 실행중인 애플리케이션 프로세스로 TCP 패킷을 demultiplexing해주기 위해서 각 애플리케이션 프로세스의 소켓은 고유한 identifier를 가지고 있는데, 이게 port 넘버이다. 0~1023까지는 well-known port라 해서 이미 HTTP(80), HTTPS(43), SSH(22), FTP(21)과 같이 잘 알려진 서비스를 위해 사용된다. 그래서 직접 개발한 애플리케이션에서 소켓을 생성해서 해당 well known port로 바인딩을 시도를 하면 바인딩 실패를 하게 된다.


flag fields

tcp header에는 flag 필드(URG/ACK/PSH/RST/SYN/FIN. 총 6bit)가 존재하는데, 각 필드가 1로 setting됬을 때 특정 커넥션 상태를 나타내거나 부가적인 의미를 제공한다.


그중에서도 ACK가 활성화되면 수신한 패킷에 대해 수신했음을 알리는 것을 의미하는데, Acknowledgement Number를 참조하면 된다.

SYN, FIN bit은 두 TCP간에 커넥션을 establish하고 close할 때 활성화되는 bit이다.


Sequence Number

TCP는 데이터를 하나의 바이트 스트림으로 보는데, 그래서 바이트 스트림의 처음부터 끝까지 0부터 시작해서 순차적으로 바이트를 넘버링한다. 그리고  하나의 큰 바이트 스트림은 MSS(Maximnum Segment Size)에 의해 segment로 분할되는데, 각 segment의 sequence number는 해당 패킷에서의 첫번째 바이트의 넘버이다.



Acknowledgement Number

acknowledgement number는 두 TCP간에 패킷을 교환할 때, 클라이언트가 보낸 패킷을 서버가 수신했을 때, 서버가 클라이언트로 패킷을 보내면서 그다음에 클라이언트로부터 받기를 기대하는 패킷의 sequence number이다.



### 3 way handshake

TCP는 connection-oriented 프로토콜이기 때문에 통신을 하고자하는 두 프로그램간에 커넥션을 맺어야한다. 이 커넥션을 맺기 위한 작업이 3 way handshake로, 두 프로그램간에 총 3개의 packet이 송수신된다.


과정(SYN - SYNACK - ACK)

0. 먼저 클라이언트(커넥션을 요청하는)측 애플리케이션 프로세스는 클라이언트 TCP에 다른 호스트(이하 서버라 지칭)의 프로세스에 커넥션을 맺고 싶다고 알린다.

  1. client’s SYN segment: 그럼 클라이언트 TCP는 서버의 TCP에 segment 헤더의 SYN bit이 활성화된 패킷(application data 없음)을 전송한다. (SYN segment)

    1. 이때 클라이언트 TCP는 최초 sequence number(짧게 client_init_seq)를 임의의 숫자로 생성한다. (임의로 sequence number를 생성하는 이유는 보안적인 공격을 막기 위해서. : CERT 2001-09)

    2. 이 SYN segment는 IP datagram으로 encapsulated되서 서버로 전송된다.

  2. server’s SYNACK segment: IP datagram이 서버로 도착하게 되면, 서버는 이 IPdatagram을 TCP SYN segment로 풀고, 커넥션에 TCP buffer와 variable에 할당한다. 그리고 클라이언트  TCP에 connection-granted segment를 전송한다.(SYNACK segment)

    1. 이 connection-granted segment는 헤더에 SYN bit이 활성화되어있고, acknowledgement number는 전송받은 SYN segment의 client_init_seq +1이 세팅된다. 그리고 마지막으로 서버측의 임의의 sequence number(짧게 server_init_seq)를 생성해서 SYNACK segment의 sequence number에 세팅한다.

  3. client’s ACK segment: 클라이언트가 SYNACK segment를 받게 되면 클라이언트 또한 커넥션에 TCP buffer와 variable을 할당한다. 그리고 클라이언트는 마지막으로 서버에게 server’s connection-granted segment를 전송한다. 이때 acknowledgement number는 server_init_seq + 1로 세팅한다.


1, 2의 SYN/SYNACK segment는 애플리케이션 데이터(payload)를 포함하지 않고, 3의 ACK segment는 포함할 수 도 있고 없을 수 도 있다.



### 4 way handshake

두 프로세스간에 데이터 교환이 끝나게 되면 TCP 커넥션이 종료되야한다. 커넥션이 종료될 때는 호스트의 리소스(커넥션에 할당한 buffers와 variables)가 해제 되어야한다.


커넥션 종료 요청은 클라이언트/서버 둘 다 요청할 수 있다. (아래에선 클라이언트의 종료 요청으로 설명하겠음.)


과정(FIN - ACK - FIN - ACK)

  1. 클라이언트 애플리케이션이 종료 요청을 하게되면, 클라이언트 TCP는 FIN bit이 활성화된 segment를 서버에 전송한다.

  2. 서버가 이를 전송받으면 클라이언트에 acknowledgement segment를 전송한다.

  3. 그리고 서버는 클라이언트에 FIN bit이 활성화된 shutdown segment를 전송한다.

  4. 이를 받은 클라이언트는 서버에 acknowlegement segment를 전송한다.



### TCP state cycle

클라이언트의 입장(Active Close 상황이라고 가정한다.; active close는 클라/서버 양측에서 모두 가능하다.)

  1. 클라이언트 TCP의 초기 state는 [CLOSED]이다.

    1. 클라이언트 애플리케이션이 소켓 오브젝트를 생성하면서 새로운 TCP 커넥션을 초기화하면, 이는 TCP가 서버의 TCP에 SYN segment를 전송하도록 한다.

  2. SYN segment를 보내면 클라이언트 TCP는 [SYN_SENT] 상태가 된다.

  3. 서버로 부터 SYNACK segment를 받게되면 클라이언트 TCP는 [ESTABLISHED] 상태에 들어선다.

    1. 이때부터 클라이언트 TCP는 payload(application-generated data)를 송수신할 수 있게 된다.

  4. 커넥션을 마치고 클라이언트가 먼저 종료를 요청해서 FIN bit이 활성화된 shutdown segment를 서버에 전송하면 클라이언트 TCP는 [FIN_WAIT_1] 상태에 들어선다. (서버로부터 FIN에 대한 acknoledgement를 기다리고 있는 상황)

  5. 서버로부터 ack를 받으면 클라이언트 TCP는 [FIN_WAIT_2] 상태에 들어선다.

    1. 서버로부터 FIN이 활성화된 shutdown segment를 기다리고 있는 상태.

  6. 서버로부터 shutdown segment를 수신받으면 클라이언트는 이에 대한 ack를 송신하고 난 후  [TIME_WAIT] 상태에 들어선다.

    1. TIME_WAIT 상태는 클라이언트 TCP가 보낸 마지막 ack(서버의 shutdown segment에 대한)가 유실되었을 경우에 마지막 ack를 재전송하도록 만든다.

    2. TIME_WAIT 상태는 구현체에 따라 다르긴한데, 대개 30sec, 1min, 2min 이다.

  7. [TIME_WAIT] 상태의 기간이 끝나게 되면 커넥션이 완전히 종료되게되고, 클라이언트측의 모든 리소스(port 번호 포함)가 해제된다.



서버 입장(Passive Close 상황이라고 가정한다.)

  1. 클라이언트 TCP와 마찬가지로 초기에는 [CLOSED] 상태이다.

  2. 클라이언트로부터의 커넥션 요청을 대기하기 위해 소켓을 생성하고 특정 port와 binding하여 커넥션을 대기한다. 이때 서버 TCP는 [LISTEN] 상태에 들어선다.

  3. 클라이언트로 부터 SYN segment(3way handshake step1)를 받게되면 서버는 SYNACK segment를 클라이언트에게 전송한 후 [SYNRCVD] 상태에 들어선다.

  4. 클라이언트로부터 SYNACK segment에 대한 ack를 받으면 서버 TCP는 [ESTABLISHED] 상태에 들어선다.

  5. 클라이언트와의 데이터 송수신을 모두 마친 후, 클라이언트가 먼저 shutdown segment를 송신한 경우 해당 segment에 대한 ACK를 송신한 후에 [CLOSE_WAIT] 상태에 들어선다.

  6. 그리고 서버의 shutdown segment를 클라이언트로 보낸 후에 [LAST_ACK] 상태에 들어선다.

  7. 클라이언트로부터 마지막 ack를 수신하면 서버측에서도 완전히 커넥션이 종료된다.



3/4 way handshake와 함께 state를 대치해보자.


댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함