[CS] 그림으로 알아보는 네트워크 - 소켓 프로그래밍과 Handshaking

emplam27·2021년 2월 15일
15

CS

목록 보기
6/6
post-thumbnail

응용계층에서 전송할 메세지를 물리계층에 전달하기 위한 역할을 전송계층에서 담당하고, 소켓 프로그래밍을 통해 진행됩니다. 어려웠던 용어들과 소켓프로그래밍 과정에 대해 그림과 함께 최대한 쉽게 풀어 써보겠습니다. 리눅스 환경을 기준으로 작성해보겠습니다.


포트(Port)?

한 컴퓨터에는 다양한 응용 프로그램들이 프로세스 단위로 실행됩니다. 각 응용프로그램이 어떤 것인지를 알 수 있게 하는 식별번호가 포트번호 입니다. 네트워크를 통해 데이터를 주고 받을 때 어떠한 프로세스가 어떠한 프로세스에게 보내는 데이터인지의 정보를 확인하는 용도입니다.

앞 포스팅과 연결하여 간단히 정리하면 IP주소를 통해 도착지 정보를, TCP/UDP 헤더를 통해 프로토콜 정보를, 포트번호를 통해 프로세스 정보를 찾아내어 최종적으로 응용프로그램에 정보를 전달합니다.



클라이언트와 서버?

네트워크에서는 기본적으로 연결을 요청하는 측과 연결요청을 받아들이는 쪽으로 짝을 이루어 구성되어 있습니다. 각각 클라이언트와 서버라고 부르며, 상대적인 관계로서 그 관계는 언제나 뒤바뀔 수 있습니다.

소켓 프로그래밍에서 클라이언트 소켓과 서버 소켓이라는 말을 자주 사용하는데, 위와 같은 의미로 이해하면 되겠습니다.



소켓(Socket)?

클라이언트와 서버 컴퓨터의 각 프로세스가 통신으로 데이터을 주고받기 위해서는 각 컴퓨터에 소켓이 필요합니다. 소켓은 파일과 비슷한 역할을 수행합니다. 클라이언트 프로세스는 반드시 소켓을 열어서 소켓에 데이터를 써서 서버에게 보내야 합니다. 또한 서버 프로세스는 소켓으로부터 받은 데이터를 읽어 사용하게 됩니다.

프로세스마다 고유한 포트번호를 가지고 있으며, 여러개의 소켓을 가질 수 있습니다. 포트번호에서 보여진 정보들인 ip주소, 프로토콜 정보, 포트번호를 통해 소켓은 생성될 소켓의 종류를 결정하여 프로세스에 맞게 생성되었다가 통신이 종료되면 소켓을 삭제합니다.

소켓은 운영체제에서 관리하는 과정으로 소프트웨어 적으로 구현되어 있습니다. 해당 프로세스의 파일 디스크립터(File Descriptor)에 저장됩니다. 파일 디스크립터는 OS 포스팅에서 자세히 다뤄보도록 하고, 지금은 열린 소켓을 저장하는 배열 정도로 생각해도 괜찮습니다.

리눅스는 기본적으로 두가지 소켓의 타입을 사용하는데, SOCK_STREAMSOCK_DGRAM 이며 각각 TCP 통신과 UDP 통신 입니다.

소켓을 이용하여 통신이 연결되는 개략적인 과정을 그림으로 나타내보겠습니다. 서버측에 그려져있는 기본소켓은 LISTEN 상태의 소켓으로 아래 소켓프로그래밍에서 다뤄보겠습니다.



소켓 프로그래밍(Socket Programing)?

위 그림에서 소켓을 만들고, 통신하고, 소켓을 없애는 과정을 소켓 프로그래밍이라고 하며 그 과정이나 상태들을 소켓 인터페이스라고 합니다. 그렇다면 소켓들은 어떻게 통신을 수행하는지 각 과정에 대해 알아보겠습니다. 아래 그림은 소켓 인터페이스이며, 클라이언트 측과 서버측의 과정이 다른것을 볼 수 있습니다.


(1) 서버 - Listen 소켓 생성

위 과정에서 서버의 프로세스는 하나의 소켓을 기본으로 가지고 있다고 하였고, 해당 소켓을 LISTEN 상태의 소켓이라 하였습니다. LISTEN 소켓은 클라이언트의 연결 요청을 기다리는 소켓으로, 항상 연결 요청을 듣는 역할만을 수행합니다. LISTEN 소켓은 연결 요청이 오게되면 본인을 복제한 새로운 소켓을 만들어 네트워크 통신을 연결합니다.

그림은 LISTEN 소켓을 만드는 과정입니다.

  1. 서버의 정보 또는 DNS를 통해 만들어야 할 소켓의 정보를 가져옵니다. (해당 그림에서는 생략하였습니다.)

  2. socket(): 속성들이 비어있는 새로운 소켓을 생성합니다.

  3. bind(): 1번에서 가져온 정보들을 소켓에게 부여(바인딩)해줍니다.

  4. listen(): 소켓을 LISTEN 상태로 만듭니다.


(2) 클라이언트 & 서버 - 연결 성립: 3 Way Handshaking

악수의 의미를 가지고 있듯이 클라이언트와 서버간의 네트워크 연결을 확인하는 과정을 뜻하며 주로 통신간의 신뢰성을 보장하는 TCP 통신의 연결 확인 과정을 말합니다. 소켓통신의 연결을 위해 3-way handshaking, 연결 종료를 위해 4-way handshaking을 진행합니다. 인터넷에 검색하게 되면 너무 많은 지식이 있기 때문에 해당 과정이 어떤 것인지는 생략하고, 이 과정이 어떤 소켓 프로그래밍 단계에서 작동하는지를 중점적으로 알아보겠습니다.

클라이언트는 네트워크 연결을 위해 하나의 소켓만 생성하면 되지만, 서버는 여러 동시에 클라이언트에게 요청을 받을 수 있기 때문에 여러개의 소켓을 가질 수 있습니다. 또 TCP 요청의 경우에는 연결이 제대로 완료되었다는 정보를 클라이언트에게 보내줘야 하는 과정역시 존재하기 때문에 이러한 과정들을 순차적으로 수행해야 합니다. 서버에 여러 요청이 들어올 경우, 서버는 이를 저장해놓고 차례대로 처리하기 위해 2개의 queue를 가지고 있습니다.

  • incomplete queue: 서버에 들어온 연결요청들을 저장해놓는 queue. 아직 완전히 연결된 상태가 아니며, 서버가 해당 요청들에 대해 클라이언트에게 연결확인 정보를 전송합니다.

  • complete queue: 클라이언트에게 연결완료 정보를 받아 완전히 연결된 상태가 된 요청정보들을 저장하는 queue. 네트워크 연결이 완료되었기 때문에 순서대로 pop되면서 본래 수행하려던 작업들을 수행합니다.


다음은 3 Way Handshaking 과정입니다. SYN 이나 ACK flag에 대한 내용은 완전히 간략화해서 적겠습니다. 클라이언트의 connect()와 서버의 accept() 함수가 종료되지 않고 해당 과정이 수행된다는 것이 특징입니다.

  1. 클라이언트는 socket()을 실행하여 CLOSED 소켓을 생성합니다.

  2. 클라이언트는 이후 connect()를 실행합니다. connect() 함수는 블록된 상태가 되어 종료되지 않습니다.

    2-1. 서버에게 연결요청 정보(SYN)를 전송합니다.

    2-2. 소켓의 상태를 SYN-SENT로 설정합니다.

  3. 서버의 LISTEN 소켓이 요청을 받게 되면, 서버는 accept()를 실행합니다. accept()함수는 블록된 상태가 되어 종료되지 않습니다.

    3-1. 클라이언트에게 연결확인 정보(SYN)를 받아 새로운 소켓을 생성하고, 소켓의 상태를 SYN-RECEIVED로 설정합니다.

    3-2. 연결 정보에 새로운 소켓을 매핑하고, incomplete queue에 push합니다.

    3-3. 클라이언트에게 연결확인 정보(SYN + ACK)를 전송합니다.

  4. 클라이언트는 서버에게 연결확인 정보(SYN + ACK)를 받고, connect() 함수는 블록이 해제됩니다. 아래 과정을 수행한 후 connect()는 종료됩니다.

    4-1. 연결확인 정보(SYN + ACK)를 받고 소켓을 ESTABLISHED로 설정합니다.

    4-2. 서버에게 연결완료 정보(ACK)를 전송합니다.

  5. 서버는 클라이언트에게 연결완료 정보(ACK)를 받고, accept() 함수는 블록이 해제됩니다. 아래 과정을 수행한 후 accept()는 종료됩니다.

    5-1. 연결완료 정보(ACK)를 받고 소켓을 ESTABLISHED로 설정합니다.

    5-2. 연결 정보를 incomplete queue에서 pop하고, incomplete queue에 push합니다.



(3) 클라이언트 & 서버 - 데이터 전송과 수신

이제 위 과정들을 통해 네트워크 연결이 완료되고 나면, 실제적으로 전달하려고 하는 정보들을 보내고 받는 과정이 이어져야 햡니다. 클라이언트와 서버는 두 과정을 모두 수행할 수 있으며, read()write()에서 수행합니다. 각각 recv()send()라고 표현하기도 합니다. 사실상 쓰고 보낸후, 받고 읽는 과정이 이기 때문에 같이쓰는게 맞는 것 같기도 합니다.

  • write(): 프로세스는 보내고자 하는 메세지나 파일들은 Buffer에 작성합니다.(write) 이후 버퍼를 소켓을 통해 다른쪽의 소켓에게 전송합니다.(send)

  • read(): 다른쪽의 소켓에게서 Buffer를 수신받습니다.(recv) 이후 버퍼에서 메세지나 파일을 읽어냅니다.(read)



(4) 클라이언트 & 서버 - 연결 해제: 4 Way Handshaking

4 Way Handshaking은 3 Way Handshaking과 반대로 클라이언트와 서버간의 네트워크 연결을 종료하는 과정을 뜻합니다. 연결이 종료되는 만큼 모든 과정이 종료되면 클라이언트와 서버의 소켓이 삭제됩니다.

다음은 4 Way Handshaking 과정입니다. 클라이언트의 close()가 먼저 실행되어 받은 정보를 이용하여 서버의 close()가 실행됩니다. 서버의 close() 과정에서 클라이언트가 보낸 모든 요청을 다 처리한 후 연결 종료를 요청하는 과정이 특징입니다.

  1. 클라이언트는 close()를 실행하여 서버에게 연결해제 요청(FIN)을 보내고, 소켓의 상태를 FIN_WAIT1로 설정합니다.

  2. 서버는 클라이언트에게 연결해제 확인(ACK) 정보를 보내고, 소켓의 상태를 CLOSE_WAIT으로 설정합니다. 서버는 남아있는 클라이언트의 요청을 모두 처리하여 클라이언트에게 보내고, 이후 close()를 실행합니다.

  3. 클라이언트는 서버에게 연결해제 확인(ACK) 정보를 받은 후, 소켓의 상태를 FIN_WAIT2로 설정합니다. 이후 서버에게서 오는 모든 요청들을 받으며 연결해제 요청(FIN)을 받기를 기다립니다.

  4. 서버는 클라이언트에게 연결해제 요청(FIN)을 보내고, 소켓의 상태를 LAST_ACK로 설정합니다.

  5. 클라이언트는 서버에게 연결해제 요청(FIN)을 받은 후 연결해제 확인(ACK) 정보를 보내고 소켓을 삭제하며 네트워크 통신을 종료합니다.

  6. 서버는 클라이언트에게 연결해제 확인(ACK) 정보를 받은 후 소켓을 삭제하며 네트워크 통신을 종료합니다.



마치며

여기까지의 과정이 소켓프로그래밍의 과정입니다. 어려웠던 소켓 프로그래밍인 만큼 그림으로 최대한 표현해봤습니다. 포스팅을 읽고 쉽게 이해하실 수 있기를 바랍니다.

profile
내가 다시 보고 싶은 글이어야 남들도 보고 싶은 글이라 생각하며 작성합니다. 공부한 내용들을 건강하게 공유하며 함께 성장하고자 합니다😊😊

2개의 댓글

comment-user-thumbnail
2022년 12월 11일

(2) 3way handshaking의 마지막 5-2부분에 incomplete queue -> complete queue 오타 수정이 필요해보입니다!

답글 달기
comment-user-thumbnail
2023년 2월 9일

안녕하세요!
제가 알기로는 accept호출전에 이미 3way handshake가 끝나는 것으로 알고있습니다!
https://stackoverflow.com/a/34677486/9567949

답글 달기