TCP 서버-클라이언트 구조

bolee·2022년 4월 6일
0
post-custom-banner

TCP 서버-클라이언트 개념

(4-1 그림)

위 그림은 서버-클라이언트의 예로 웹 서버와 웹 클라이언트가 동작하는 모습니다. HTTP은 TCP에 기반한 프로토콜이기 때문에 웹 서버-클라이언트는 대표적인 TCP 서버-클라이언트 응용 프로그램이라고 할 수 있다.

TCP 서버-클라이언트의 핵심 동작을 개념적으로 정리하면 다음과 같다. (괄호 안에는 사용할 소켓 함수 표시)

  1. 서버는 먼저 실행하여 클라이언트가 접속하기를 기다린다.(listen)
  2. 클라이언트는 서버에 접속(connect)하여 데이터를 보낸다.(send)
  3. 서버는 클라이언트 접속을 수용하고(accept) 클라이언트가 보낸 데이터를 받아(recv) 처리한다.
  4. 서버는 철리한 데이터를 클라이언트에 보낸다.(send)
  5. 클라이언트는 서버가 보낸 데이터를 받아서(recv) 처리한다.
  6. 데이터를 주고받는 과젖을 모두 마치면 접속을 끊는다.(closesocket)

(4-2 그림)

이와 같은 방식은 웹 서버-클라이언트, 텔넷 서버-클라이언트, FTP 서버-클라이언트 등에도 동일하게 적용된다.

TCP 서버-클라이언트 동작 원리

(4-3 그림)

위 그림은 TCP 서버와 TCP 클라이언트가 연결되어 통신을 수행하는 과정을 보여준다.

  • (a): 서버는 소켓을 생성한 후 클라이언트가 접속하기 기다린다. 이때 서버가 사용하는 소켓은 특정 포트 번호와 결합되어 있어 이 포트 번호로 접속하는 클라이언트만 수용할 수 있다.
  • (b): 클라이언트가 서버에 접속한다. 이때 TCP 프로토콜 수준에서 연결 설정을 위한 패킷 교환이 일어난다.
    • TCP 3 way handshake
      TCP 3 way handshake는 연결 상태를 확인하는 것이다. 데이터를 본격적으로 전송하기 전에 서로 접속 요청과 요청 수락을 주고 받아 연결상태를 확인한 후 데이터를 전송한다. 일반적으로 연결 상태를 확인하기 위해 3번 주고 받기 때문에 3번 악수하는 것과 같다고 하여 3 way handshake라고 한다.
  • (c): TCP 프로토콜 수준의 연결 절차가 끝나면, 서버는 접속한 클라이언트와 통신할 수 있는 새로운 소켓을 생성한다. 이 소켓을 이용해 서버는 클라이언트와 데이터를 주고받는다. 기존 소켓은 새로운 클라이언트 접속을 수용하는 용도로 계속 사용한다.
  • (d): 두 클라이언트가 접속한 후의 상태를 나타낸 것이다. 서버에는 소켓이 총 3개 존재하며, 이 중 두 소켓을 접속한 클라이언트와 통신하는 용도로 사용한다.

TCP 서버-클라이언트가 통신하는 상황을 일반적인 형태로 나타내면 아래 그림과 같다. 서버쪽 소켓과 클라이언트쪽 소켓이 일대일로 대응하는 것을 알 수 잇다. 'TCP 클라이언트 #n'처럼 클라이언트 1개가 소켓 2개 이상 사용해 서버에 접속할 수도 있다.

TCP 서버-클라이언트 실습

IPv4 기반으로 동작하는 간단한 TCP 서버-클라이언트를 작성하고 테스트해 볼 것이다.
테스트에서 사용할 서버와 클라이언트 예제의 동작을 미리 살펴보면 아래와 같다.

  • 서버: 클라이언트가 보낸 데이터를 받아서(recv) 이를 문자열로 간주해 무조건 화면에 출력한다.(printf) 그리고 받은 데이터를 변경 없이 다시 클라이언트에 보낸다.(send) 받은 데이터를 그대로 다시 보낸다는 뜻으로 에코 서버(echo erver)라고 부르겠다.
  • 클라이언트: 사용자가 키보드로 입력한(fget) 문자열을 서버에 보낸다.(send) 서버가 받은 데이터를 그대로 돌려보내면, 클라이언트는 이를 받아서(recv) 화면에 출력한다.(printf) 에코 서버와 통신한다는 의미로 에코 클라이언트(echo client)라고 부르겠다.

(4-5 그림)

소스 코드의 경우 해당 링크를 참조하면 된다.
해당 코드의 경우 실습의 편의를 위해 서버와 클라이언트를 같은 컴퓨터에서 실행하는 것을 가정하고 있다. 서로 다른 컴퓨터에서 실행하려면 TCPClient.cpp 파일의 6행을 서버의 IP 주소로 변경해야 한다. 서버는 포트 변호를 9000을 사용하고 있기 때문에 다른 포트 번호를 사용하려면 TCPServer.cpp 파일의 6행과 TCPClient.cpp 파일의 7행을 변경하면 된다.
테스트는 아래 순서에 따라 실행해보면 된다.

서버와 클라이언트 실행과 연결 확인

  1. TCP 서버(TCPServer.exe)를 실행한다. 초기에는 아무것도 출력되지 않는다.
    (4-6 그림)

  2. 명령 프롬프트를 실행 후 netstat -a -n 명령을 실행한다.

    • netstat: TCP/IP 네트워크 연결과 통계 정보를 표시하는 유틸리티로 윈도우 운영체제에서 기본으로 제공
      • -a: 모든 연결과 연결 대기 포트를 표시하는 옵션
      • -n: 주소와 포트 번호를 숫자 형식으로 표시하는 옵션

    (4-7 그림)

    TCP 포트 번호 9000의 상태가 LISTENING(연결 대기 중)임을 볼 수 있다.

  3. TCP 클라이언트(TCPClient.exe)를 실행한다.
    (4-8 그림)

  4. 다시 netstat -a -n 명령을 실행한다. 예제 프로그램과 관련된 정보는 총 3개인데, 각각 포트 번호 9000, 9000, 49186을 사용하고 있다. 첫 번째 행은 LISTENING(연결 대기 중)상태이고, 나머지 두 생은 ESTABLISHED(연결됨)상태임을 알 수 있다.
    (4-9 그림)

최종적으로 아래 그림과 같은 상태가 되는 것이다.

(4-10 그림)

데이터 전송과 수신

  1. 클라이언트에서 글자를 입력하고 Enter키를 누르면 입력 데이터가 서버에 전송된다. 클라이언트는 송신 바이트 수를 표시하고, 서버는 클라이언트의 IP 주소와 포트 번호, 클라이언트로부터 받은 데이터를 화면에 출력한다. 서버는 받은 데이터를 클라이언트에 되돌려주기 때문에, 클라이언트는 자신이 보낸 데이터를 다시 받게 된다. 클라이언트 화면에는 수신 바이트 수와 받은 데이터가 표시된다.

    (4-11 그림)

클라이언트 정상 종료

  1. 글자를 입력하지 않고 그냥 Enter키를 누르면 클라이언트는 종료하고, 서버 화면에 다음과 같이 표시된다.

    (4-12 그림)

  2. 다시 netstat -a -n 명령을 실행해 네트워크 연결 상태를 확인한다. LISTENING 상태인 포트(9000)와 TIME_WAIT상태인 포트(49186)가 존재함을 알 수 있다. 서버는 계속 실행중이므로 연결 대기 중인 포트 번호(9000)은 유지되고 있지만, 클라이언트와 통신하던 소켓을 사라졌다. 또한 클라이언트는 종료했음에도 사용하던 포트 번호(49186)가 사라지지 않고 TIME_WAIT상태로 남아있는 것이다.

    (4-13 그림)

최종적으로 아래 그림과 같은 상태가 되는 것이다.

클라이언트 비정상 종료

  1. 이번에는 TCP 클라이언트를 다시 실행해 TCP 서버에 데이터를 몇 개 보낸 후 Ctrl + c를 눌러 강제 종료한다. 클라이언트가 강제 종료되었음을 암시하는 오류 메세지가 서버에 표시된다.
    (4-15 그림)
  2. netstat -a -n 명령을 실행해 네트워크 연결 상태를 확인해보자. 이번에는 LISTENING 상태인(9000)만 존재하고 TIME_WAIT상태인 포트는 존재하지 않는다.
    (4-16 그림)

참고 자료
김성우 저, "TCP/IP 윈도우 소켓 프로그래밍", 한빛아카데미, 2018

post-custom-banner

0개의 댓글