Socket?
소켓은 네트워크상의 두 프로그램 간의 통신을 위한 엔드포인트로,
소켓 주소 정보를 사용하여 데이터 송수신을 관리하는 프로그래밍 인터페이스이다.
네트워크 기능을 사용하려는 애플리케이션(프로세스)은 소켓을 열어서, 소켓 인터페이스를 통해 네트워크 작업을 수행한다.
소켓 자체는 TCP나 UDP에 종속된 개념이 아니다. 네트워크 통신을 할 때, 각 통신주체가 데이터를 주고 받는 출발지와 도착지 역할을 하는 대상을 통칭한다.
다만 현대 네트워킹에서는 TCP, UDP가 흥하면서 TCP, UDP 프로토콜을 기반으로 하는 소켓을 주로 쓰고 있고, 때문에 소켓 == TCP 소켓, UDP 소켓으로 통용되는 감이 없지않아 있다.
네트워크 통신을 위한 소켓을 Stream 소켓과 Datagram 소켓 유형으로 나누어 볼 수 있다. 이들은 사용하는 프로토콜과 데이터 전송 방식에서 차이가 있다. 각각 TCP와 UDP가 대명사이다.
일반적으로 TCP (Transmission Control Protocol)를 사용한다.
웹 서버, 이메일 전송, 파일 전송 등 데이터의 정확성과 순서가 중요한 애플리케이션에서 주로 사용된다.
일반적으로 UDP (User Datagram Protocol)를 사용한다.
실시간 스트리밍, 온라인 게임, 비디오 회의 등 실시간성이 중요하고 일부 패킷 손실이 허용되는 애플리케이션에서 주로 사용된다.
위에서 소켓을 한 문장으로 정의한 바는 다음과 같다.
소켓은 네트워크상의 두 프로그램 간의 통신을 위한 엔드포인트로,
소켓 주소 정보를 사용하여 데이터 송수신을 관리하는 프로그래밍 인터페이스이다.
그러나 이것만으로는 인터넷 네트워크 통신에서의 소켓의 정체를 파악하기에 완전하지 않다.
소켓을 여러 관점에서 바라보면 다음과 같이 정의할 수 있다.
Socket 이란?
1. 개발자에게는, 소켓은 네트워크를 통한 데이터 입출력을 위한 file
2. 프로세스에게는 네트워크 세계로의 인터페이스 (= 포트 역할)
3. 네트워크 세계에서는, 데이터 통신의 엔드포인트
4. 각 소켓은 <프로토콜 + IP 주소 + 포트 넘버> 라는 소켓 주소로 식별된다.
(= 각 프로세스의 포트를 유니크하게 식별하기 위한 주소)
Socket 연결? (in TCP)
1. 연결 설정 시: 소켓주소 활용 = <프로토콜 + IP 주소 + 포트 넘버>
2. 연결 유지 시: 연결 정보 활용 = <src IP 주소, src 포트, dest IP 주소, dest 포트>
아래 'Socket 연결' 내용은 TCP 통신에 한정된 얘기다. (근데 TCP가 거의 표준이니깐..)
지금부터는 위 요약 정리가 대체 뭔 말인지를 알아보자.
우선 소켓은 인터넷 상에서 데이터를 주고 받는 엔드포인트 역할임과 동시에, 이를 위해 인터넷 상에 존재하는 각 PORT를 유니크하게 식별하기 위한 주소이기도 하다.
즉, 설계 목적부터 알 수 있듯이 각각의 socket은 인터넷 상에서 유니크하다. (뒤에서 보겠지만 사실은 유니크하게 식별되지 않을 수 있다.)
원래는 TCP 프로토콜에서 주로 소켓이 쓰였는데, 소켓이라는 개념이 없던 UDP에서도 소켓 개념을 가져와 쓰기 시작했고, UDP도 주류로 올라오게 되면서 프로토콜 구분도 필요하게 되었다.
그래서 Socket = <프로토콜 + IP 주소 + 포트 넘버> 가 되었다.
만약, 하나의 프로세스에서 두 개의 소켓을 열었다고 해보자. 그럼 IP와 포트 넘버가 같을 수 있다.
그러나 만약 각각의 프로토콜을 다르게 했다면, 3개를 합친 조합은 유니크하기 때문에 소켓의 조건에 어긋나지 않는다.
Connection이라는 건 socket과 socket을 연결하는 것을 말한다. (src socket -> dest socket)
위에서 소켓 식별 방법을 <프로토콜 + IP 주소 + 포트 넘버> 로 정의했는데,
실제로는 상황에 따라 이 연결 정보도 소켓 식별의 역할을 한다.
정리하자면, TCP 소켓의 동작 과정은 다음과 같다.
클라이언트 쪽에서도 같은 IP와 포트 넘버를 갖는 여러개의 소켓이 가능하다. 이 경우는 OS 레벨에서 알아서 포트 번호를 바인딩하는 경우에 발생 가능하다.
OS는 포트 넘버를 할당할 때 아무도 쓰고있지 않은 포트 넘버를 할당하는데, 이미 소켓이 엄청 많아서 빈 포트 넘버가 없을 수 있다. 그러면 어쩔수없이 중복된 걸 할당하도록 설계되어 있다.
이때 기존 소켓과 주소가 동일한 해당 소켓으로 기존 소켓이 연결되어있던 서버에 연결을 요청하면 어떻게 될까?
TCP 스펙상 <src ip, port, dest ip, port>는 유니크해야 하므로, 이 경우에는 연결할 수 없다.
이럴 때는 또 다른 서버를 열어서 또 다른 listening 소켓을 열어줘야 한다.
소켓이라는 대상을 개발자의 관점에서 다시 한번 해석해보자. '프로세스는 소켓을 열어서, 소켓을 통해 네트워크 통신을 한다..' 라는 말이 무엇을 의미할까?
TCP/IP 4계층을 더 뭉뚱그려 나누면 애플리케이션 영역, Kernel 영역, H/W 영역으로 나눌 수 있는데, 우리 개발자 입장에서 보면 이를 또 다시 1) 네트워크 기능을 활용하는 애플리케이션 레벨과 2) 이를 지원하는 시스템 레벨(커널 & 하드웨어)로 나눌 수 있다.
개발자가 복잡한 네트워크 인프라의 내부 사정을 다 파악하고 컨트롤해야 한다고 생각하면 너무 비효율적이지 않나? 애플리케이션 개발자는 서비스 개발에 집중하는게 효율적이다. 따라서, 시스템은 애플리케이션이 네트워크 기능을 사용할 수 있도록 프로그래밍 인터페이스를 제공한다. 이 프로그래밍 인터페이스를 소켓이라고 한다.
때문에, 반드시 소켓을 사용해야만 네트워크 기능 이용 가능하다. 이를 Socket programming이라고 부른다. 소켓 프로그래밍을 통해 개발자들은 네트워크 상의 다른 프로세스와 데이터를 주고받는 식의 무언가를 개발할 수 있다.
Q. 난 지금까지 HTTP 개발했는데, 소켓 프로그래밍인지 뭔지 한 적 없는데?
ㅇㅇ. 보통 개발자가 socket을 직접 조작해서 통신 기능을 구현할 일은 적다.
왜냐하면 socket 프로그래밍은 우리가 사용하는 라이브러리나 모듈로 추상화되어있기 때문이다. 우리는 일반적으로 application layer에서도 최상단(OSI로 치면 L7)에서 작업한다. (HTTP도 여기에 속한 프로토콜이다.) application layer의 프로토콜은 보통 라이브러리나 모듈 형태로 하위 layer의 기능을 제공한다.
만일 라이브러리나 모듈의 내부의 소스코드를 열어보면 socket을 활용했다는 걸 볼 수 있을 것이다.
'이게 대체 무슨 소리야???' 싶지만..
리눅스 등 Unix 계열, 윈도우는 Socket 형태로 네트워크 기능을 제공한다.
컴퓨터 입장에선 네트워크도 입출력 장치나 마찬가지이다. 따라서 소켓은 곧 file과 같다.
개발자는 파일 디스크립터(file descriptor)를 통해 파일을 다루는 것과 똑같은 원리로 소켓을 다루게 된다.
초등학생도 바보같다고 생각할 질문이지만, 생각보다 파일은 더 우아한 존재였다.
Unix 계열 OS는 '모든 것은 파일이다 (Everything is a file)'라는 철학을 가지고 있다.
아니, 우리가 평소에 더블클릭해서 실행하는 '파일'이라는게 그렇게 대단한 존재라니?
입출력(I/O)은 근본적으로 메인 메모리 <-> 입출력장치(디스크, 터미널, 네트워크) 간에 데이터를 복사하는 작업이다.
Unix 시스템은 입출력(I/O) 작업을 파일로 추상화하여 컨트롤하고 관리할 수 있도록 지원한다. 이를 파일 시스템(File System)이라고 한다. 즉, 파일 시스템은 입출력 작업의 세부적인 과정을 숨기고, 사용자에게는 직관적이고 간단한 인터페이스를 제공하는 시스템이다.
파일 시스템은 컴퓨터에서 데이터를 저장하고 관리하는 책장과 같다.
우리가 문서나 정보를 파일에 정리하고 책장에 꽂아 두는 행위, 그리고 편하게 책장에서 꺼내보는 행위를 떠올리면 된다.
예를 들어, 특정 .exe 파일을 더블클릭하여 프로그램을 실행하는 상황을 생각해보자.
이 과정에서 발생하는 여러 단계는 실제로는 매우 복잡하다:
그러나 파일 시스템 덕분에 우리는 이 모든 복잡한 과정을 단순한 '더블 클릭' 동작으로 수행할 수 있는 것이다.
위 예시는 개발자 뿐만 아니라 컴퓨터를 사용하는 누구나 자주 사용하므로 쉽게 와닿는다.
네트워크에서도 마찬가지의 법칙이 적용된다.
예를 들어, 네트워크를 통해 데이터를 수신하는 과정은 다음과 같다:
이 모든 과정은 소켓 인터페이스를 통해 간단히 수행된다.
위에서 언급했지만, 프로그래밍 측면에서 '소켓'은 시스템 레벨에서 제공하는 네트워크를 위한 인터페이스이다. (= 소켓 인터페이스)
OS의 관점에서 보면?? 소켓은 네트워크에 의한 입출력을 조작하는 파일에 불과한 것이다. 때문에 일반 파일에 대한 개념이 대부분 적용된다. (파일 생성, 열기, 닫기, 삭제, write, read, execute)
아마 네트워크 프로그래밍을 하는 개발자가 아니라면 네트워크를 위한 파일 시스템을 굳이 열고 쓸 일이 없을 것이기 때문에, 이 개념이 바로 직관적으로 와닿지는 않는다. 보통 더 상위 레벨의 프로세스(서비스)가 동작하는 과정에 네트워크 기능은 숨겨져있다.
파일 디스크립터(식별자)는 Unix 및 Unix 계열 OS에서 파일, 소켓, 또는 기타 I/O 리소스를 참조하기 위해 사용되는 정수 값이다.
파일 디스크립터는 Unix 계열 시스템에서 I/O 리소스를 효율적으로 관리하는 데 중요한 역할을 한다. 파일 디스크립터를 사용하여 파일이나 소켓을 열고, 데이터를 읽고 쓰며, 리소스를 닫는 일련의 과정을 수행한다.
이를 통해 프로세스는 시스템 리소스에 접근하고 제어할 수 있다.
파일 디스크립터 사용하기
파일 디스크립터와 리소스 관리
<쉬운코드> [1부] 프로토콜 표준 스펙에서 정의한 Socket(소켓), Port(포트), TCP connection(연결) 개념
<쉬운코드> [2부] 프로토콜 표준과는 다르게 실제로는 소켓(Socket)이 어떻게 식별되는가?
<널널한 개발자 TV> 소켓 01 00 소켓의 본질에 대한 이해
네트워크 프로그래밍 | Proxy Lab | echo 서버 구현 (소켓 프로그래밍 공부) (2) | 2023.11.21 |
---|---|
네트워크 모델 | (5) 데이터 단위와 흐름 이해하기 (1) | 2023.11.20 |
네트워크 모델 | (3) TCP, UDP 프로토콜 소개 (0) | 2023.11.18 |
네트워크 모델 | (2) 네트워크 주소 체계(Port, IP, MAC), IP 라우팅 (1) | 2023.11.18 |
네트워크 모델 | (1) OSI 모델, TCP/IP 모델 개요 (1) | 2023.11.18 |