1. 접속의 의미

‘접속’은 실제로 서버와 연결되는 과정만을 의미하지 않는다. 접속하기 위한 준비 단계도 접속을 하기 위해서 필수로 거쳐야 하는 과정이므로 이 또한 ‘접속’ 이라고 표현한다.

소켓을 만든 직후에는 소켓에 의미있는 정보가 없다. 어느 IP 와 PORT 에 있는 소켓과 연결할 것인지 등에 대한 정보가 아직 작성되어 있지 않다. connect() 를 호출하여 이러한 정보들을 저장하는데, 이 과정도 접속의 한 단계이다.

또한 서버도 소켓을 생성한 직후에는 의미있는 정보가 없다. 클라이언트에서 접속을 시도하고, 이를 서버가 받았을 때 서버의 소켓에 의미있는 정보를 저장한다. 이 과정도 접속의 한 단계이다.

데이터를 송수신할 때 송수신한 데이터를 임시로 저장하는 버퍼 메모리를 확보하는 과정도 접속을 위해 필수적인 단계이므로 접속의 한 단계라고 볼 수 있다. 즉, 실제로 클라이언트와 서버가 접속을 하기 위해 준비하는 모든 단계를 ‘접속’ 이라고 볼 수 있다.

2. 맨 앞부분에 제어 정보를 기록한 헤더를 배치한다

1962D782-5696-46C3-ACF9-517817293766.jpeg

D4C0948A-CF02-448F-A199-6FCD73D2A6CA.jpeg

프로토콜을 이용하여 서버와 통신할 때 보내는 HTTP 메시지를 그대로 보내지 않는다. 비교적 큰 메시지를 여러 개의 작은 단위로 분할하여 패킷이라는 단위로 만든 후 패킷을 송신한다. 이 패킷들의 헤더에 다양한 제어 정보 를 기록하여 전달한다.

패킷에 작성되는 제어 정보와 소켓에 작성되어 있는 제어 정보는 다르다. 일반적으로 소켓은 OS 에서 제공하는 프로토콜 스택에 따라 결정된다. 사용하는 프로토콜 스택이 필요로 하는 정보를 기반으로 소켓의 제어 정보가 결정된다. 따라서 클라이언트와 서버가 다른 OS 를 사용한다면 양측의 소켓에서 관리하는 제어 정보는 다를 수 있다. 그러면 다른 OS 간의 통신은 어떻게 동작할까? 바로 패킷의 헤더에 정의하는 제어 정보가 동일하기 때문에 가능하다. 양측의 소켓의 제어 정보가 다르더라도 패킷의 헤더 제어 정보는 동일하도록 맞추어 OS 에 관계없이 통신이 가능하다.

소켓은 각각의 PC 에서 관리하는 제어 정보로, 외부 서버에서는 이에 대해 알 수 없다. 외부와 통신하기 위해서 소켓의 정보를 이용하여 패킷을 정의한다. (패킷 : 외부 서버와 통신하기 위한 전달체)

3. 접속 동작의 실체

애플리케이션에서 connect() 를 호출하면 OS 의 프로토콜 스택에서는 다음과 같은 과정을 거쳐서 서버와 파이프를 연결한다.

TCP 담당 부분에서 소켓의 정보를 이용하여 TCP 헤더를 작성한다. 클라이언트(송신처) 와 서버(수신처) 의 포트 정보를 작성하고, 즉 어느 소켓와 연결해야 하는지 결정하고 컨트롤 비트인 SYN 의 비트를 1 로 변경한다. 작성한 TCP 헤더를 IP 담당 부분에게 건네주어 송신하도록 의뢰한다. 그러면 IP 담당 부분이 패킷 송신 동작을 실행하고 네트워크를 통해 패킷이 서버에 도착하면 서버 측의 IP 담당 부분이 TCP 담당 부분에게 건네준다. 그러면 TCP 담당 부분이 TCP 헤더를 조사하여 수신처 포트 번호와 일치하는 소켓을 찾아낸다. 찾아낸 소켓의 상태 정보를 변경한 후 클라이언트에게 응답을 보낸다.

클라이언트와 마찬가지로 서버의 소켓에도 SYN 과 함께 ACK 비트를 1 로 변경한다. 다시 서버는 변경한 TCP 헤더를 IP 담당 부분에게 보내 클라이언트에게 반송을 의뢰한다.

패킷이 클라이언트에게 도착하면 IP 담당 부분을 경유하여 TCP 담당 부분에 도착한다. TCP 헤더의 컨트롤 비트를 보고 서버와 접속이 성공적인지 확인한다. SYN 이 1 이면 접속 성공이므로 소켓에 서버의 IP 주소나 포트 번호 등과 함께 소켓에 접속 완료 상태를 기록한다. 마지막으로 서버에게 모든 패킷이 성공적으로 도착했다고 알리기 위해 서버로부터 받아온 ACK 비트를 1 로 만든 TCP 헤더를 반송한다. 이것으로 서버와 접속 과정이 끝난다.

이렇게 서버와의 커넥션이 연결되면 프로토콜 스택의 접속 과정이 끝나므로 connect() 의 실행이 끝나면서 애플리케이션을 제어할 수 있게 된다.