3.4. 소켓과 네트워크 연결

소켓은 특히 네트워크를 통한 통신에 사용된다. 소켓은 본래 유닉스 시스템의 BSD 계열에서 개발되었지만 일반적으로 다른 유닉스 계열 시스템으로 이식가능하다: 리눅스와 System V 변형들도 또한 소켓을 지원하는데 오픈 그룹의 Single Unix Specification [Open Group 1997] 은 소켓 지원을 요구하고 있다. System V 는 전통적으로 호환되지 않는 다른 네트워크 통신 인터페이스를 사용했지만 솔라리스같은 시스템이 소켓 지원을 포함한다는 것을 언급하는 것은 가치가 있다. Socket(2) 은 통신을 위한 끝점 (endpoint) 를 생성하여 파일에 대한 open(2) 과 유사한 방식으로 기술자 (descriptor) 를 반환한다. 소켓 매개변수는 인터넷 도메인 (TCP/IP 버전 4), Novell 의 IPX 또는 ``유닉스 도메인" 과 같은 프로토콜 계열과 타입을 지정한다. 서버는 곧이어 일반적으로 bind(2), listen(2) 과 accept(2) 또는 select(2) 를 호출하며 클라이언트는 일반적으로 bind(2) (생략될 수도 있다) 와 connect(2) 를 호출한다. 더욱 자세한 정보는 이러한 루틴 각각의 맨 페이지를 보라. 맨 페이지에서 소켓 사용방법을 이해하는 것은 어려울 수 있는데 이러한 호출을 함께 어떻게 사용하는지를 배우려면 Hall "Beej" [1999] 와 같은 다른 논문을 참조할 수 있다.

``유닉스 도메인 소켓"은 실제 네트워크 프로토콜을 나타내지는 않는데 다만 동일 머신상의 소켓에 접속할 수 있다 (표준 리눅스 커널에 대한 이 글을 작성하는 시점에는). 스트림으로 사용될 때 이는 네임드 파이프와 아주 유사하지만 상당한 장점을 갖고 있다. 특히 유닉스 도메인 소켓은 접속 지향으로 소켓으로의 새로운 각 접속은 네임드 파이프와는 매우 다르게 새로운 통신 채널을 생성한다. 이 특성때문에 유닉스 도메인 소켓은 대개 많은 중요한 서비스에 대해 IPC 를 구현하기 위해 네임드 파이프 대신 사용된다. 언네임드 파이프를 가질 수 있듯이 socketpair(2) 를 사용하여 언네임드 유닉스 도메인 소켓을 가질 수 있는데 이는 언네임드 파이프와 유사한 방식으로 IPC 에 대해 유용하다.

유닉스 도메인 소켓은 보안과 관련해서 몇가지 재미있는 함축된 의미를 갖고 있다. 첫째 유닉스 도메인 소켓이 파일시스템에 나타나며 이에 적용되는 stat(2) 를 가질 수 있음에도 불구하고 open(2) 을 사용해서 이를 열 수는 없다 (socket(2) 와 friends 인터페이스를 사용해야 한다). 두번째 유닉스 도메인 소켓은 프로세스간 파일 기술자를 전달하는데 사용될 수 있다 (그저 파일 내용이 아닌). 다른 모든 IPC 메카니즘에서 사용할 수 없는 이러한 색다른 능력은 모든 타입의 체계 (scheme) 를 해킹하는데 사용되어 왔다 (기술자는 컴퓨터 과학 분야에서 기본적으로 ``능력"의 제한된 버전으로 사용될 수 있다). 파일 기술자는 sendmsg(2) 를 사용하여 보내지는데 msg (메시지) 의 msg_control 필드는 제어 메시지 헤더의 배열을 가리킨다 (msg_controllen 필드가 배열에 포함된 바이트수를 지정해야 한다). 각 제어 메시지는 데이타 다음에 오는 cmsghdr 구조체로 이 목적을 위해 cmsg_type 을 SCM_RIGHTS 로 설정해야 한다. 파일기술자는 recvmsg(2) 를 통해 검색되며 이때부터 유사한 방식으로 추적된다. 솔직히 이 특징은 매우 색다르지만 알만한 가치가 있다.

리눅스 2.2 는 유닉스 도메인 소켓에서 부가적인 특징을 지원하는데 peer 의 "credentials" (pid, uid 와 gid) 을 얻을 수 있다. 다음은 예제 코드이다:

 /* fd= 식별하기를 원하는 클라이언트에 접속된 유닉스 도메인 소켓의 파일 기술자 */

 struct ucred cr;
 int cl=sizeof(cr);

 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl)==0) {
   printf("Peer's pid=%d, uid=%d, gid=%d\n",
           cr.pid, cr.uid, cr.gid);

표준 유닉스에서는 1024 미만의 TCP 와 UDP 지역 포트 넘버로의 바인딩은 루트 권한을 가져야 하며 모든 프로세스는 1024 또는 그 이상의 unbound 포트 넘버에 바인드할 수 있는 것이 관례이다. 리눅스는 이 관례를 더욱 명확하게 따르는데, 리눅스는 1024 미만의 포트 넘버로 바인딩하기 위해서는 CAP_NET_BIND_SERVICE 능력을 갖는 프로세스를 필요로한다.; 이 능력은 보통 euid 가 0 인 프로세스만이 갖는다. 관심이 있다면 리눅스 소스를 살펴봄으로써 이를 확인할 수 있는데 리눅스 2.2.12 의 /usr/src/linux/net/ipv4/af_inet.c 파일에서 inet_bind() 함수를 보라.