데이터 송수신 동작의 개요
- IP 주소를 조사했으면 IP 주소의 상대, 여기에서는 액세스 대상 웹 서버에 메시지를 송신하도록 OS의 내부에 있는 '프로토콜 스택'에 의뢰합니다. 웹 서버에 보내는 HTTP의 메시지는 디지털 데이터이므로 디지털 데이터를 송신하도록 의뢰한다고 해도 좋을 것입니다. 이 동작은 네트워크를 이용하는 애플리케이션 전체에 공통입니다.
- OS 내부의 프로토콜 스택에 메시지 송신 동작을 의뢰할 때는 Socket 라이브러리 프로그램 부품을 결정된 순번대로 호출합니다.
- 파이프와 같은 것을 통해 데이터가 흐릅니다.
- 파이프 양끝에 있는 데이터의 출입구를 '소켓'이라고 부릅니다.
- 실제로는 먼저 서버측에서 소켓을 만들고, 소켓에 클라이언트가 파이프를 연결하기를 기다립니다.
- 클라이언트 측에서도 소켓을 만들고, 소켓에서 파이프를 늘려 서버측의 소켓에 연결합니다.
- 이로써 양쪽의 소켓이 연결되면 준비가 완료된 것입니다.
- 앞에서 설명한 대로 소켓에서 데이터를 쏟아붓듯이 데이터 송수신 동작을 실행합니다.
송수신이 끝난 후
- 데이터를 전부 보내고 나면 연갤했던 파이프가 분리됩니다.
- 파이프를 연결할 때는 클라이언트측에서 서버측을 향해 연결했지만, 파이프 분리할 때는 어느 쪽에서 분리해도 상관없습니다.
데이터 송수신 동작의 요약
- 소켓을 만듭니다(소켓 작성 단계)
- 서버측의 소켓에 파이프를 연결합니다.(접속 단계).
- 데이터를 송수신합니다.(송수신 단계).
- 파이프를 분리하고 소켓을 말소합니다.(연결 끊기 단계).
- 앞의 네 가지 동작을 실행하는 것은 OS 내부의 프로토콜 스택입니다. 브라우저 등의 애플리케이션은 프로토콜 스택에 의뢰해서 파이프를 연결하거나 데이터를 쏟아붓습니다.
- 의뢰 동작은 Socket 라이브러리에 넣은 프로그램 부품을 호출하여 실행되지만, 데이터 송수신용 프로그램 부품은 애플리케이션에서 의뢰받은 내용을 그대로 프로토콜 스택에 전달하는 중개역을 수행할 뿐 실질적인 작업은 하지 않습니다.
- 그래서 Socket 라이브러리와 프로토콜 스택을 한 몸인 것으로 보고 일체화 된 동작을 설명하는 쪽이 이해하기 쉽습니다.
소켓의 작성 단계
- 소켓 라이브러리의 socket이라는 프로그램 부품만 호출하면 됩니다.(여기서는 socket 프로그램 부품, Socket은 라이브러리, 소켓은 파이프의 양끝에 있는 출입구를 가리킵니다.)
- socket을 호출한 후의 동작은 리졸버를 호출했을 때와 같이 socket 내부에 제어가 넘어가서 소켓을 만드는 동작을 실행하고, 이것이 끝나면 애플리케이션으로 제어가 돌아옵니다.
- 소켓이 생기면 디스크립터(번호표 같은 것으로 소켓을 식별)라는 것이 돌아오므로 애플리케이션은 이것을 받아서 메모리에 기록해 둡니다.
- 브라우저를 2개의 창을 열어 2개의 웹 서버에 동시에 액세스 하는 경우 복수의 소켓이 생기고 이럴 때 디스크립터에 대한 필요성이 존재하게 됩니다.
파이프를 연결하는 접속 단계
- 만든 소켓을 서버측의 소켓에 접속하도록 프로토콜 스택에 의뢰합니다.
- 애플리케이션은 Socket 라이브러리의 connect라는 프로그램 부품을 호출하여 이 의뢰 동작을 실행합니다.
- 여기서 요점은 connect를 호출 할 때 지정하는 디스크립터, 서버의 IP 주소, 포트 번호라는 세 가지 값입니다.
- 최초의 디스크립터는 소켓을 만들 때 돌아온 디스크립터입니다.
- 여기서 지정한 디스크립터는 connect가 프로토콜 스택에 통지합니다.
- 프로토콜 스택이 통지받은 디스크립터를 보고 어느 소켓을 서버측의 소켓에 접속할지 판단하여 접속 동작을 실행합니다.
- IP 주소 : 네트워크에 존재하는 각 컴퓨터를 식별하기 위해 각각에 서로 다른 값을 할당한 것(각 기기에 할당되는 것이 아니라 기기에 장착된 각각의 네트워크용 하드웨어에 할당됩니다. 그러므로 복수의 네트워크 하드웨어를 장착한 기기에는 복수의 주소가 할당됩니다.
- 즉 IP 주소로 지정할 수 있는 것은 네트워크의 어느 컴퓨터인가 하는 것까지입니다.
- 접속 동작은 상대 측의 소켓에 대해 이루어지므로 소켓을 지정해야 하는데, IP주소로는 소켓까지 지정할 수 없습니다. 전화를 걸었을 때 "OO님 계십니까?"라고 말하여 통화할 상대를 바꿔달라는 중간 과정이 필요한데, 이 중간 과정이 '포트 번호'입니다.
- IP 주소와 포트 번호를 지정해야 어느 컴퓨터의 어느 소켓과 접속할지를 분명히 지정할 수 있습니다.
- 디스크립터는 컴퓨터 한 대의 내부에서 소켓을 식별하기 위해 사용하지만, 포트 번호는 접속 상대측에서 소켓을 식별하기 위해 사용합니다. (디스크립터로 포트 번호가 하는 일을 할 수 없습니다. 또한, 포트 번호로도 내부 소켓을 식별하는 것은 문제가 있습니다.)
서버에서 클라이언트 측의 소켓 번호를 아는 방법
- 먼저 클라이언트측의 소켓의 포트 번호는 소켓을 만들 때 프로토콜 스택이 적당한 값을 골라서 할ㅇ당 합니다.
- 이 값을 프로토콜 스택이 접속 동작을 실행할 때 서버측에 통지합니다.
정리
- connect를 호출하면 프로토콜 스택이 접속 동작을 실행합니다.
- 상대와 연결되면 프로토콜 스택은 연결된 상대의 IP주소나 포트 번호 등의 정보를 소켓에 기록합니다. 이로써 데이터 송수신이 가능한 상태가 됩니다.
- 디스크립터 : 애플리케이션이 소켓을 식별하는 것
- IP 주소와 포트 번호 : 클라이언트와 서버 간에 상대의 소켓을 식별하는 것
메시지를 주는 송신 단계
- 소켓이 상대 측과 연결되면 그 다음은 간단합니다. 소켓에서 데이터를 송신하면 상대 측의 소켓에 데이터가 도착합니다.
- 그러면 애플리케이션은 소켓을 직접 다룰 수 있으므로 Socket 라이브러를 통해 프로토콜 스택에 일을 의뢰합니다. 그래서 write라는 프로그램 부품을 사용하게 됩니다.
- 사용자가 입력한 URL을 바탕으로 만든 HTTP의 리퀘스트 메시지가 여기에서 말하는 송신데이터입니다. 그리고 write를 호출할 때 디스크립터와 송신 데이터를 지정합니다.
- 그러면 프로토콜 스택이 송신 데이터를 서버에게 송신합니다.
- 그러면 서버는 수신 동작을 실행하여 받은 데이터의 내용을 조사하고 적절한 처리를 실행하여 응답 메시지를 반송합니다.
메시지를 받는 수신 단계
- 수신할 때는 Socket 라이브러리의 read라는 프로그램 부품을 통해 프로토콜 스택에 수신 동작을 의뢰합니다.
- 이 때 수신한 응답 메시지를 저장하기 위한 메모리 영역을 지정하는데, 이 메모리 영역을 수신 버퍼라고 부릅니다.
- 그러면 응답 메시지가 돌아올 때 read가 받아서 수신 버퍼에 저장합니다. 수신 버퍼는 애플리케이션 프로그램의 내부에 마련된 메모리 영역이므로 수신 버퍼에 메시지를 저장한 시점에서 메시지를 애플리케이션에게 건네줍니다.
연결 끊기 단계
- 그 후 Socket 라이브러리의 close라는 함수를 호출하여 연결 끊기 단계로 들어가도록 의뢰합니다. 그러면 소켓 사이를 연결한 파이프와 같은 것이 분리되고 소켓도 말소됩니다.
- 이 때의 동작을 자세히 보면 웹에서 사용하는 HTTP 프로토콜에서는 본래 응답 메시지의 송신을 완료했을 때 웹 서버측에서 연결 끊기 동작(클라이언트나 서버 중 어느 쪽이 close를 실행시키는 지 차이가 있습니다. 웹은 서버가 먼저 close를 실행합니다.)을 실행하므로 먼저 웹 서버측에서 close를 호출하여 연결을 끊습니다.
- 그러면 클라이언트 측도 소켓을 연결 끊기 단계로 들어갑니다.
- 그리고 브라우저가 read로 수신 동작을 의뢰했을 때 read는 송수신 동작이 완료되어 연결이 끊겼다는 사실을 브라우저에게 통지합니다.
- 이로써 송수신이 종료되었다는 것을 알 수 있으므로 브라우저에서도 close를 호출하여 연결 끊기 단계에 들어갑니다.
총정리
- 메시지를 실제로 송수신하는 것은 프로토콜 스택, LAN 드라이버, LAN 어댑터 이 세가지입니다.
- 리졸버 : 도메인명에서 IP 주소를 조사할 때 DNS 서버에 조회 메시지를 보내는 것. 즉 도메인명을 IP 주소로 변환해 준다고 생각할 수도 있어서 답을 찾아내거나 해결한다는 뜻의 리졸버라고 쓰입니다.