04 프로토콜 스택에 메시지 송신을 의뢰한다.
본 설명은 책 “성공과 실패를 결정하는 1%의 네트워크 원리”를 읽으며 제 나름대로 해석하고 정리해 보았습니다.
1. 데이터 송수신 동작의 개요
이제 IP 주소를 알았으면 엑세스 대상 웹서버에 메시지를 송신하도록 OS 내부에 있는 프로토콜 스택에 의뢰를 한다. 데이터를 송 수신 하는 동작은 단연 브라우저 뿐 아니라 네트워크를 이용하는 애플리케이션 전체의 공통이다.
이 동작에서도 DNS 서버에 IP 주소를 조회할때처럼 Socket 라이브러리에 들어있는 프로그램 부품을 이용한다. 본 동작은 IP 주소를 조회할 때처럼 프로그램 부품을 하나씩 호출하고 끝나는 것이아니라, 결정된 순번대로 호출해야하므로 조금 복잡하다.
Socket 라이브러리를 이용한 데이터 송 수신을 쉽게 말하자면, 데이터를 송 수신하는 컴퓨터 사이에 데이터의 통로 같은 것이 있고, 이것을 통해 데이터가 흐르면서 상대측에 도착하는데, 통로는 파이프와 같은 것이라고 생각하면 된다.
위 그림만 보면 처음부터 파이프가 존재하는 것이라고 생각할 수 있지만 송 수신 동작을 시작하기전 양자 사이를 파이프로 연결하는 동작이 필요하다.
이 부분의 요점은 데이터 출입구 즉 소켓 이다. 이 소켓은 먼저 서버 측에서 소켓을 만들고 소켓에 클라이언트가 파이프를 연결하기를 기다린다. 클라이언트가 파이프를 만드는 과정에서도 클라이언트가 소켓을 만들고 소켓에서 파이프를 늘려서 서버측 소켓에 연결하는 것이다.
데이터를 전부 보내고 나면 연결했던 파이프가 분리된다, 처음에 연결은 클라이언트에서 서버쪽으로 했지만 분리시에는 어느 쪽에서 먼저 하든 사실 상관 없다.
결국, 송 수신 동작은 4단계로 요약할 수 있다,
- 소켓을 만든다. (소켓 작성 단계)
- 서버측의 소켓에 파이프를 연결한다. ( 접속단계)
- 데이터를 송 수신한다. (송 수신 단계)
- 파이프를 분리하고 소켓을 말소한다. (연결 끊기 단계)
이 단계로 Socket 라이브러리 안의 프로그램 부품을 호출하며 송수신 동적을 실행하는데 한가지 더 알아야 할 개념이 있다. 이 동작을 실행하는 것은 앞 장에서도 언급했었지만, OS 내부의 프로토콜 스택이다. 결론적으로 Socket 라이브러리의 프로그램 부품이 실질적인 송수신 동작을 하는 것이아니라 OS 프로토콜 스택에 의뢰 하는 것이다. 따라서 Socket 라이브러리 프로그램 부품이 어떤 식으로 동작하는지 구체적으로 알기 보다는 이 Socket 라이브러리와 프로토콜 스택을 한 몸으로 보고 이해하는 것이 편하다.
2. 소켓의 작성 단계
그래서 앞에서 말한 4단계 중 먼저 소켓 작성 단계에 대해 살펴보자.
소켓을 만드는 과정은 꽤 간단하다. 소켓 라이브러리의 socket
이라는 프로그램 부품만 호출하면 된다. socket
을 호출한 후 동작은 리졸버를 호출했을 때와 같이 socket
내부에 제어가 넘어가서 소켓을 만드는 동작을 실행하고, 끝나면 다시 제어가 어플리케이션으로 돌아온다.
소켓이 생기면 디스크립터 라는 것이 돌아오므로 어플리케이션은 이것을 받아 메모리에 기록한다.
디스크립터 소켓을 식별하기 위해 사용하는 것으로 소켓에 할당한 번호와 같은 것이다.
컴퓨터 내부에서는 복수의 데이터 송수신 동작이 동시에 진행되는 경우 복수개의 소켓을 만들어야 한다. 따라서 각 소켓을 식별하기 위해 필요한 것이 디스크립터 인것이다.
3. 파이프를 연결하는 접속단계
이제 만든 소켓을 서버 측의 소켓에 접속하도록 프로토콜 스택에 의뢰하는 단계 이다. 이 동작은 Socket 라이브러리의 connect
프로그램 부품을 호출하여 이 의뢰 동작을 실행한다. 여기서 필요한 것은 디스크립터, 서버의 IP 주소, 포트 번호
세가지 값이다.
디스크립터, 서버의 IP 주소는 왜 필요한지 앞의 설명들을 이해했다면 알것이다. 그런데 포트 번호 가 왜 필요할까? 이유는 IP 주소로는 네트워크의 어느 컴퓨터인 것 까지인가만 알 수 있을 뿐 상대소켓을 지정해야하는데 어느 소켓과 접속할지를 알아야 한다. 이때 필요한 것이 포트 번호 이다.
그렇다면 이 서버측의 포트번호 를 어디서 알 수 있냐? 라고 물어보면 클라이언트도 모르고 URL에서도 볼 수 없고 DNS 서버에서 조회하는것도 아니다. 사실 대단할 것은 없고 애플리케이션의 종류에 따라 미리 결정된 값을 사용한다는 규칙이 있을 뿐이다. 즉, 웹은 80번 메일은 25번이다. 즉, 브라우저에서 웹 서버에 엑세스할 때의 포트 번호는 80번으로 결정되어 있는 샘이다.
그렇다면 클라이언트 측의 소켓 번호는 누가 지정하냐? 이것은 클라이언트측에서 소켓을 만들 때 프로토콜 스택이 적당한 값을 골라서 할당한다. 그리고 이 값은 프로토콜 스택이 접속 동작을 실행할 때 서버측에 통지한다.
4. 메시지를 주고받는 송 수신 단계
소켓이 상대측과 연결된 뒤, 이제 파이프가 생겼으므로 애플리케이션은 소켓을 직접 다룰 수 있어 Socket 라이브러리를 통해 프로토콜 스택에 일을 의뢰한다. 이는 write
라는 프로그램 부품을 사용한다.
- 애플리케이션은 송신 데이터 메모리를 준비 (송신데이터 = 리퀘스트 메시지)
- write를 호출할 때 디스크립터와 송신 데이터를 지정한다.
- 프로토콜 스택이 송신데이터를 서버에게 송신한다. (소켓에는 연결된 상대가 기록되어 있으므로 디스크립터로 소켓을 지정하면 연결된 상대가 판명되어 그 곳을 향해 데이터를 송신한다.)
- 서버는 수신 동작을 실행하여 받은 데이터를 바탕으로 응답 메시지를 반송한다.
- 응답한 메시지를 수신하기 위해 Socket의
read
프로그램 부품을 통해 프로토콜 스택에 수신 동작을 의뢰한다. (응답메시지를 저장하기 위한 메모리 영역을 지정해야하는데 이것이 바로 수신버퍼) - 응답 메시지가 돌아올때
read
가 받아서 수신 버퍼에 저장한다. - 수신 버퍼에 미시지를 저장한 시점에 메시지를 애플리케이션에 건내준다.
5. 연결 끊기 단계에서 송 수신이 종료된다
이제 모든 데이터를 주고 받았으면 Socket 라이브러리의 close
라는 프로그램 부품을 호출하여 연결 끊기 단계로 들아가도록 의뢰한다.