socket() 함수를 알아보자!
이 글의 목적은 socket() 함수 하나를 완벽히 이해하는데 있다.
1. 소켓의 생성
// linux
int socket(int domain, int typem int protocol);
// windows
SOCKET socket(int af, int type, int protocol);
domian: 소켓이 사용할 프로토콜 체계(protocol family) 전달
type: 소켓의 데이터 전송방식에 대한 정보 전달
protocol: 두 컴퓨터간 통신에 사용될 프로토콜 정보 전달
1.1 프로토콜 체계(Protocol Family)
socket() 함수의 첫번째 인자로 소켓이 사용가능한 프로토콜의 여러 부류 중 하나를 선택해서 전달해야한다. 이 포스팅은 IPv4를 기준으로 하기에, PF_INET을 넘겨주면된다. 프로토콜 체계의 종류는 아래의 표와 같다. (이는 sys/socket.h에 선언된 프로토콜 기준)
이름 |
프로토콜 체계(Protocol Family) |
IPv4 인터넷 프로토콜 체계 |
PF_INET |
IPv6 인터넷 프로토콜 체계 | PF_INET6 |
로컬 통신을 위한 UNIX 프로토콜 체계 | PF_LOCAL |
Low Level 소켓을 위한 프로토콜 체계 | PF_PACKET |
IPX 노벨 프로토콜 체계 | PF_IPX |
1.2 소켓의 타입(Type)
소켓의 타입이란 소켓의 데이터 전송방식을 의마하는데, 이 정보를 socket() 함수의 두번째 인자로 전달해야한다. 그래야 생성되는 소켓이 데이터를 전송하는 방식을 결정할 수 있기 때문이다. 여기서 이런 의문이 들수도 있다. socket() 함수의 첫번째 인자로 프로토콜 체계를 넘겨주었는데 왜 굳이 타입을 지정해줘야 하는가? 이에 대한 답으로 프로토콜 체계가 정해졌다고해서 데이터 전송방식까지 정해진것은 아니기에 그렇다고 답할 수 있다. 앞서 전달한 PF_INET에도 둘 이상의 데이터 전송방식이 존재한다. 그럼 이어서 두 가지 데이터 전송방식을 설명하겠다.
1.2.1 소켓의 타입1: 연결지향형 소켓(SOCK_STREAM)
socket() 함수의 두번째 인자로 SOCK_STREAM을 전달하면 연결지향형 소켓이 된다. 연결지향형 소켓의 특징을 정리하면 다음과 같다.
- 전송 중 데이터의 소멸, 누락이 없다.
- 전송 순서대로 데이터가 수신된다.
- 송수신 데이터의 경계(Boundary)가 없다.
1.2.2 소켓의 타입2: 비연결지향형 소켓(SOCK_DGRAM)
socket() 함수의 두번째 인자로 SOCK_DGRAM을 전달하면 비연결지향형 소켓이 된다. 비연결지향형 소켓의 특징을 정리하면 다음과 같다.
- 데이터의 소멸, 누락의 위험이 있다.
- 전송된 순서에 상관없이 빠른 전송만을 목표로 한다.
- 데이터 간에 경계가 존재하고, 한번에 보낼 수 있는 데이터의 제한이 있다.
1.3 프로토콜 선택
이제 socket() 함수의 세번째 인자로 소켓이 최종적으로 사용할 프로토콜을 전달하면 된다. 사실 우리가 주로 사용하는 PF_INET의 대표적인 데이터 전송방식인 SOCK_STREAM, SOCK_DGRAM은 각각 하나의 프로토콜(TCP, UDP)만 존재하므로 세번째 인자를 넘겨주지 않아도 된다. 다만 "하나의 프로토콜 체계안에 데이터 전송방식이 동일한 프로토콜이 둘 이상 존재하는 경우"에는 세번째 인자를 필요로 한다. 하여 SOCK_STREAM, SOCK_DGRAM의 경우 굳이 넘겨주자면 각각 IPPROTO_TCP, IPPROTO_UDP로 넘겨주면된다.
Appendix: 윈도우와 리눅스 기반 소켓 함수의 차이
위의 소켓 생성 코드에서 본것처럼, 윈도우의 경우 socket() 함수의 반환형이 SOCKET이다. 이는 (MS에서 정의한) 소켓의 핸들값을 저장하기 위한 자료형이다. 윈도우에서도 리눅스에서 처럼 socket() 은 정수를 반환하지만, 리눅스에선 이를 파일기스크립터라고 부르는 반면, 윈도우는 이를 핸들이라 부른다. 이는 운영체제의 구조적 차이 때문에 오는 것이다. 그러니 SOCKET 자료형을 소켓의 핸들값을 저장하는 자료형 정도로만 기억하자.
응용계층에서 socket()을 호출하면 이는 곧 운영체제의 시스템 콜로 넘어가서, 운영체제가 소켓을 생성한다. 운영체제 내부에서 소켓은 하나의 자료형일 뿐이다. (응용프로그램에서 소켓은 네트워크 통신을 위한 소켓 라이브러리를 의미한다.)
하여 socket 자료형 변수가 할당된 메모리의 시작주소를 변경하여 핸들 형태로 응용 프로그램에게 넘겨준다. 이후 응용프로그램은 이 핸들 값을 통해 소켓에 접근한다. 이는 운영체제의 관리 영역에 응용 프로그램의 직접적인 접근을 차단하기 위한 windows의 정책이다.