[kocw 이미정] 9. Socket programming with UDP and TCP, Transport-layer services, Multiplexing and demultiplexing

이건회·2022년 1월 24일
0

네트워크

목록 보기
9/24

  • 애플리케이션 프로토콜은 애플리케이션 프로그램을 지원한다. 보편적 네트워크 애플리케이션 프로그램을 만들때는 소켓을 사용한다. 소켓은 마치 프로그래머가 작성하는 프로그램과 운영체제가 제어하는 transport 사이의 인터페이스다. 예시로 클라이언트가 키보드에서 소문자로 타이핑하는 것을 읽어들여 서버에 보내고 서버에서 대문자로 바꾸어 다시 클라이언트에 보내는 과정을 살펴볼 것이다. 소켓 프로그래밍은 transport를 부탁할때 udp 혹은 tcp에 부탁한다. 이 두 가지를 살펴보도록 할 것이다
  • udp로 소켓 프로그래밍하는 과정을 보겠다. udp는 클라이언트와 서버 간의 커넥션은 셋업하지 않고 바로 메세지를 보낸다. 따라서 데이터를 보내기 전 handshaking이 없다. 그리고 각 데이터마다 ip목적지 주소와 포트번호를 붙여서 보내준다. 서버의 경우 프로그래머가 명시적으로 포트번호를 지정한다. 그러나 클라이언트의 포트번호는 알려져 있지 않으므로 서버는 서버가 받은 세트먼트로부터 그것을 ip주소와 함께 추출한다.

  • 클라이언트 서버 통신이 이루어지기 위해서는 서버 프로세스가 실행되고 있어야 한다. 프로세스가 실행되기 위해서는 서버 소켓을 만든다. 서버는 소켓을 통해 데이터를 주고받는다. 클라이언트 측에서도 역시 클라이언트 소켓을 만들어야 ip주소와 포트번호를 세그먼트에 붙여 내보낼 수 있다. 이를 다시 서버소켓을 통해 읽어들일 수 있다. 또 역시 서버 소켓을 통해 응답을 써서 클라이언트 쪽으로 줄 수 있다. 이때 어느 클라이언트에게 가는지 ip주소와 포트번호를 명시해야 한다. 그런데 클라이언트 ip주소와 포트번호는 클라이언트 프로세스도 모른다. 이는 클라이언트 프로세스가 소켓을 만들때 운영체제가 명시적이 아닌 암시적으로 매핑을 하기 때문이다. 그래서 서버는 클라이언트로부터 온 데이터에 이 번호가 붙어 있기 때문에 이를 추출해 포트번호를 알아낸다. 따라서 서버가 이 정보를 통해 클라이언트에 정보를 보내면 클라이언트 소켓을 통해 데이터를 읽어들이고 클라이언트 소켓은 닫힌다.

  • 위는 파이썬에서 udp 클라이언트 소켓 프로그래밍의 예시다. 소켓 라이브러리를 상속하고 서버의 호스트 네임과 서버 소켓의 포트번호를 지정한다. 이후 클라이언트 소켓을 생성하고 인자로 데이터 딜리버리에 사용할 네트워크와 udp transport를 사용할 것임을 명시한다. 이를 명시하는 이유는 운영체제가 소켓에 클라이언트 주소와 포트번호를 매핑하기 때문에 포트번호의 주소가 어느 패밀리의 주소이고 어떤 트랜스포트를 사용하는지 알려줘야 하기 때문이다. 이후 키보드로부터 사용자의 인풋을 받고, 클라이언트 소켓에 메세지를 써주고 서버네임과 서버포트를 인자로 넣어준다. 또 서버가 수정된 센텐스를 보내면 클라이언트 소켓을 통해 받는다. 그러면 그 메세지를 출력하고 소켓을 닫는다.


  • 위는 파이썬에서 udp 서버 소켓 프로그래밍의 예시다. 서버 포트를 지정하고 서버소켓을 만든다. 그 다음 서버소켓과 서버 포트번호를 바인딩 시킨다. 이렇게 서버의 포트번호가 명시적으로 드러나는 것이 클라이언트 소켓과의 차이다. 서버가 받을 준비가 됐다는 메세지가 뜨면 루프를 영구적으로 돈다. 서버 소켓에 메세지의 데이터와 데이터를 보낸 이의 주소가 도착하면 message에 데이터를 뽑고, clientaddress라는 변수에 주소를 뽑는다. 메세지를 대문자로 바꾼 후 modifiedmessage 변수에 집어넣고 서버 소켓을 통해 클라이언트에 내보내는데, 첫 인자로 내보낼 데이터, 두 번째 인자로 클라이언트의 주소를 넣는다. 이는 데이터로부터 받은 메세지에서 추출한 것이다. 이 주소는 클라이언트 프로세스가 모른다. 운영체제가 암묵적으로 할당한 것이기 때문이다. 이는 서버 측에서 주소를 추출해서 데이터를 내보낼때 명시해 준다.

  • 다음은 tcp 소켓 프로그래밍이다. 이 역시 서버가 실행 중이여야 하고 서버는 소켓을 생성하는데 이 용도는 클라이언트의 컨택트를 받아들이기만 하는 것이다. 소켓을 만들면 클라이언트는 tcp 소켓을 통해 데이터를 내보내려 할 텐데 핸드셰이킹이 먼저 필요하다. 이를 위해 본인이 접촉할 서버의 ip주소와 포트번호를 명시해준다. 그러면 클라이언트 소켓을 생성하여 클라이언트 tcp가 서버 tcp와 커넥션을 맺는다. 서버 쪽 tcp에서는 클라이언트의 접촉을 받아들이고 해당 클라이언트만을 위한 소켓을 새로 생성한다. 따라서 tcp로 데이터를 주고받을 때는 커넥션을 셋업 하고 나면 목적지를 명시하지 않는다. 목적지를 명시하지 않아도 새롭게 생성된 소켓을 통해 내려온 데이터는 오직 하나의 클라이언트로만 전달되는 것을 tcp가 인지하고 있기 때문이다. 또 새로운 클라이언트마다 소켓을 만드므로 tcp는 각 커넥션마다 소켓을 별도로 열고 있다. 그래서 한 소켓을 통해 주고받는 동안 다른 소켓으로 주고받을 수 있다. 이렇게 하는 이유는 tcp는 byte-stream을 주고받기 때문이다. udp는 각 메세지가 독립적이므로 메세지를 하나 받고 답을 보내주면 끝이다. 그러나 tcp는 한 클라이언트와 커넥션을 맺으면 임의적인 길이의 바이트스트림을 주고받기 때문에 그것을 주고 받는 동안 다른 클라이언트와 교환을 못하면 안 된다.

  • 다음은 tcp를 통한 클라이언트-서버 소켓 인터렉션이다. 먼저 서버가 서버 소켓을 만들면 서버소켓의 포트번호를 명시적으로 지정하고 bind시킨다. 이후 커넥션 요청이 들어오면 서버 소켓을 새롭게 생성하고 이를 커넥션 소켓이라 부른다. 이게 실행되기 위해서는 어느 클라이언트가 소켓을 만들고 tcp가 커넥션 셋업이 되어야 한다. 그럼 udp와 같이 요청을 내보내고 커넥션 소켓을 통해 요청을 읽고 응답하면 커넥션 소켓만을 닫고, 클라이언트 소켓은 응답을 받고 소켓을 닫는다.

  • 위는 tcp 클라이언트의 예시이다. 역시 서버와 포트번호를 명시하고 소켓을 생성한다. 이후 서버네임과 포트번호를 적어 서버쪽 tcp와 커넥션을 맺는다. 이후 키보드로부터 입력을 받아들이고 클라이언트 소켓에 내보낼 데이터를 명시해 서버로 보낸다. 서버에서 응답이 오면 클라이언트 소켓이 이를 받아들이고 (modifiedsentence) 메세지를 올려보낸 후 클라이언트 소켓을 닫는다.

  • 다음은 tcp 서버 프로세스다. 역시 서버 포트번호를 명시한 후 서버 소켓을 생성한다. 서버소켓을 생성하면 자동으로 운영체제와 ip주소와 포트번호를 할당한다. 그러면 그 서버소켓을 bind라는 함수를 통해서 프로그래머가 원하는 포트번호로 매핑을 시킨다. 이것이 이미 사용하는 포트번호면 실행되는 포트번호라는 메세지를 보내고 아니면 이것으로 포트번호를 결정한다. 그 다음 서버소켓.listen으로 클라이언트 요청이 들어올때까지 듣고 있는 것이다. 이후 서버는 준비가 됐다는 메세지를 출력하고 루프로 들어간다. 클라이언트의 커넥트 요청이 오면 그것을 받아들이고 그 결과를 가지고 새로운 커넥션 소켓을 생성한다. 커넥션 소켓의 포트번호는 12000이 아닌 새로운 포트번호고 프로그래머가 알 필요가 없다. addr는 클라이언트쪽 주소다. 역시 프로그래머가 알 필요가 없다. tcp 계층에서 이미 알기 때문에 자동 배달되기 때문이다. 이후 커넥션 소켓을 통해 이 내용을 받고 대문자로 바꿔 커넥션 소켓을 통해 클라이언트 소켓으로 보내고 소켓을 닫는다.

  • 클라이언트 측에서 계속해서 입력을 받아 보내는 구조일 경우 소켓을 닫지 않고 계속 while루프에서 open하고 특별한 요청이 오면 커넥션 소켓을 닫게 할 수도 있다.

Chapter 3. Transport layer

  • 목표: transport 계층의 원리 이해, 인터넷에서 실제 사용되는 udp와 tcp 이해
  • transport 계층 서비스는 애플래케이션 프로세스간 논리적 커뮤니케이션이다. 경우에 따라 애플리케이션이 배달을 요청하는 메세지를 세그먼트로 짤라서 보내기도 한다.
  • 네트워크 계층에서 제공하는 서비스가 메세지의 host to host 서비스를 제공한다면 transport 계층에서는 일단 목적지 호스트로 온 메세지를 목적지 프로세스로 전달하는 것이다(프로세스 투 프로세스).
  • tcp는 congestion/flow control과 커넥션 셋업을 통해 reliable하고 in-order(순차적)한 서비스를 제공하나, udp는 ip에 제공하는 서비스가 없다. 그러나 둘 다 delay/bandwidth guarantee는 하지 않는다.
  • 트랜스포트 계층에서 제공하는 가장 기본적인 서비스는 Multiplexing and demultiplexing이다. 서버가 클라이언트마다 서버를 별도로 열어 놓는다면 보내는 측(클라이언트 호스트)에서는 여러 개의 애플리케이션들이 모두 별도의 소켓을 통해 transport 계층으로 메세지 전송을 요청한다. 이 때 trasport 계층에서는 udp의 경우 여러 프로세스들이 내려보내는 메세지를 멀티플렉싱 한다. 메세지마다 헤더를 통해 목적지가 어디인지 도장을 찍어서 모두 한 길로 내보내는 것이다. 그러면 받는 측에서는 네트워크 계층을 통해 한줄로 올라온 메세지를 클라이언트 측에서 찍은 도장을 확인하여 transport 계층에서 목적지 애플리케이션 프로세스로 배달해준다. 즉 demultiplexing이 일어나는 것이다.
  • 어떻게 demultiplexing이 일어날까. 세그먼트는 헤더(포트번호)와 페이로드(앱 데이터)로 나눠진다. 이 포트번호를 보고 demultiplexing이 일어난다. 그런데 final destination의 주소는 포트번호와 네트워크 주소 두 가지로 구성되는데, 세그먼트의 헤더에는 포트번호 밖에 없는데 네트워크 계층으로 내려가면 네트워크 계층에서 스스로의 호스트 id를 붙여준다.
  • udp와 같은 connectionless의 경우 demultiflexing이 어떻게 일어날까. demultiflexing은 받는 측에서 일어난다. 소켓을 만들면 호스트-로컬 포트번호가 운영체제에 의해 암시적으로 생성된다. udp소켓을 통해 데이터그램을 보낼 때는 반드시 목적지의 ip주소와 포트번호를 명시해야 한다. 호스트가 udp 세그먼트를 받으면 세그먼트의 목적지 포트번호를 받아 그 포트번호에 해당하는 소켓으로 세그먼트로 전달한다.
  • udp는 어떤 서버 프로세스가 소켓 하나만을 열어놓으므로 여러 클라이언트로부터 온 메세지가 하나의 서버 소켓으로 들어온다. 그런데 포트번호 만으로 demultiplexing을 하면 다른 클라이언트에서 똑같은 포트번호가 전달될 수 있어 오류가 날 수 있으므로, 목적지를 추출할 때 포트 번호 뿐이 아닌 ip주소까지도 추출해야 한다.
profile
하마드

0개의 댓글