관리 메뉴

개발노트

TCP 연결과 해제 본문

기타

TCP 연결과 해제

YoonGwon 2022. 10. 27. 10:39

https://brunch.co.kr/@dreaminz/5

 

5. TCP 연결과 해제

A라는 상태에서 어떤 과정을 거치면 B라는 상태가 될까 | TCP는 연결할 때 3-way handshake를 하며, 연결을 끊을 때는 4-way handshake를 진행한다. 여기서 handshake는 악수로 만나면 3번의 과정을 통해 악수

brunch.co.kr

 

 

 

 

TCP

TCP 연결을 유지 하려면 양쪽 종점에 TCP를 설정 한다.

TCP는 정해진 STATE 중 한가지 상태에 머물게 되고 상위 계층의 응용 프로그램에 의한 시스템 호출이나 상대편  TCP에서 전송한 TCP 세그먼트 수신 등의 이벤트에 반응하면서 다른 상태로 전이 된다.

 

TCP STATE

 

 

 LISTEN  상대편 TCP로부터 연결 요청을 기다림 
 SYN_SENT  SOCKET를 이용해 생성하는 경우로 소켓을 연 응용 프로그램을 대신해 TCP가 SYN을 전송하고 연결을 완료 할 수 있도록 상대 응답을 기다림
 SYN_RECV  이전에 LISTEN상태에 있던 TCP가 SYN을 수신해 SYN/ACK를 응답으로 전송 한 뒤 다음 연결을 완료 할 수 있도록 상대 TCP로부터 ACK기다림
 ESTABLISHED  상대편 TCP와의 연결 수립을 완료. 이제 두 TCP간 데이터 세그먼트를 주고 받을 수 있다.
 FIN_WAIT1  응용 프로그램에서 연결을 닫음. 상대 TCP의 연결을 종료하도록 FIN을 전송하고 ACK를 기다림.
 FIN_WAIT2  FIN_WAIT1 상태에 잇던 TCP가 상대편 TCP로부터 ACK를 수신
 CLOSING  FIN_WAIT1 상태에서 ACK를 기다리던 TCP가 ACK가 아닌 FIN을 수신. 상대방 TCP에서도 종료를 수행 했을 경우 발생.
 TIME_WAIT  FIN을 수신한 TCP는 연결이 안정적으로 종료 되고 네트워크 상에 잔존하는 중복 세그먼트가 만료 될 수 있도록  TIME_WAIT상태에서 정해진 시간 동안 대기 한다. 정해진 시간이 지나면 연결이 종료되며 관련 커널 자원도 해제 한다.
 CLOSE_WAIT  상대편 TCP로부터 FIN을 수신 했다.
 LAST_ACK  기존에 CLOSE_WAIT 상태에 있던 TCP는 상대편 TCP로 FIN을 전송 한 뒤 ACK를 기다린다. ACK를 수신하면 연결이 종료되며 커널 자원이 해제 된다. 

 

 

 

 

 

 TCP 상태 전이 다이어그램

 

 

 

 

 

TCP 연결 수립

서버가 listen()을 호출해 소켓을 수동적으로 연 뒤 accept()를 호출해 연결이 수립 될 때 까지 블록 한다.

클라이언트는 서버의 수동 소켓과 연결 할 수 있도록 connect()를 호출해서 능동적으로 소켓을 연다.

 

 

three-way handshake

 

 

 

 

 

 

 

 

TCP 연결 종료 순서

1. 서버 or 클라이언트에서 close를 수행..

2. 반대편도 close 수행

 

클라이언트가 close를 먼저 했을 경우

1. 클라는 서버로 FIN 전송

2. 서버는 ACK로 응답. ACK를 응답 한 후로 서버에서 발생하는 read는 EOF가 된다.

3. 서버도 close를 호출하면서 연결 종료하면 서버는 클라이언트로 FIN을 전송.

4. 클라이언트는 서버에 대한 답신으로 ACK 응답.

 

* BSD 소켓 구현은 MSL을 30초로 설정했다. 따라서 TIME_WAIT 상태는 총 60초의 생명 주기를 갖는다. (그러나 RFC1122는 MSL값을 2분으로 권고하여 이를 따르는 구현에서는 4분간 지속 된다)

* MSL은 IP 패킷이 TTL(time-to-live) 한도는 넘는 데 걸리는 시간을 추정한 값이다.

 

 

 

 

 

 

조심 TIME_WAIT

이전글에 대한 설명에서 보면 TIME_WAIT는.. 새 인카네이션(incarnation) TCP 연결이 수립되기 전에 네트워크 상에 잔존하는 중복 세그먼트가 만료 될 수 있도록 정해진 시간 동안 대기하는게 있음.

근데 그 전에 접속을 요청하게 되면 새인카네이션을 만들수 없게 한다. 서버가 재식될 경우 TIME_WAIT 상태의 TCP주소로 소켓을 결속하려해서 EADDRINUSE 에러가( 'address already in use' )발생한다. 

 

 

이 에러를 해결하기 위해서는 SO_REUSEADDR 옵션을 사용 한다.

일반적으로 EADDRINUSE 가 발생할 수 있는 두가지 시나리오가 있다.

 

1. 기존 연결에서 클라이언트에 연결된 서버가 CLOSE를 호출하거나 크래시로 인해 종료가 됬고 결국  TCP종점은 TIME_WAIT 상태에서 2MSL 타임아웃 시간만큼 대기한다.

2. 서버에서 클라 연결을 처리할 자식 프로세서를 생성. 나중에 서버는 종료 됬지만 자식 프로세서는 클라이언트에 서비스를 계속 제공. 이 경우 TCP종점은 서버의 잘 알려진 포트를 이용해 TCP종점을 유지한다.

 

TCP 소켓은 아래와같이 4튜플을 조합해 연결을 식별 할 수 있다.

{ local-IP-address, local-port, foreign-IP-address, foreign-port }

TCP 규격은 이와 같은 튜플이 유일성을 지닐것을 요구함. 즉 매순간에는 오직 하나의 연결만이 존재 할 수 있다.

 

 

SO_REUSEADDR 옵션의 기본값은 0, 비활성화다. 아래 코드는 SO_REUSEADDR 옵션을 사용한 예제다..

int sockfd, optval;

sockfd = socket( AF_INET, SOCK_STREAM, 0 );
if ( sockfd == -1 ) errExit("socket");

optval = 1;
if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval) ) == -1 ) errExit("socket");
if ( bind( sockfd, &addr, addrlen ) == -1 ) errExit("bind");
if ( listen( sockfd, backlog ) == -1 ) errExit("listen");

 

 

 

 

 

 

소켓 모니터링 netstat

인터넷과 유닉스 도메인 소켓의 상태를 표시한다.

 

 

 -a  대기하는 소켓을 포함한 모든 소켓 정보 출력 
 -e  소켓 소유자의 사용자 ID를 포함한 확장 정보 출력
 -c  매초 소켓 정보를 연속적으로 재출력
 -l  대기하는 소켓에 대한 정보만 출력
 -n  IP주소, 포트번호, 사용자명을 숫자 형식으로 표현
 -p  소켓이 소속된 프로세스 ID 와 프로그램명 출력
 --inet  인터넷 도메인 소켓 정보 출력
 --tcp  인터넷 도메인 TCP 소켓 정보 출력
 --udp  인터넷 도메인 UDP 소켓 정보 출력
 --unix  유닉스 도메인 소켓 정보 출력

 

 

proto : 소켓 프로토콜 정보

Recv-Q : 아직 읽지 않고 수신 버퍼에 남은 바이트 수

Send-Q : 전송 버퍼 큐에 추가된 바이트 수

LocalAddress : 소켓이 결속된 주소, 호스트 부분에 사용하는 *는 와일드카드  IP주소이다.

Foreign Address : 상대편 주소 정보 *:*는 상대편 주소 정보가 없음을 의미 한다.

State : 소켓의 현재 상태 정보

출처: https://z-man.tistory.com/148 [지맨네집:티스토리]

728x90

'기타' 카테고리의 다른 글

OSGI란?  (0) 2022.07.28
X25 와 TCP/IP  (0) 2022.07.28
[메시지 지향 미들웨어:MOM] ActiveMQ, rabbitMQ, Kafka  (0) 2021.01.26
Scale-out & Scale-up 이란  (0) 2021.01.14
윈도우에 개발도구 AtomEditor 설치법  (0) 2020.12.15