본문 바로가기

진리는어디에

[socket] socket 함수에 관한 고찰

들어가며

프로그래밍을 공부하면서 최소한 소켓 프로그래밍라는 것에 대해서 한 두번은 들어 보셨다고 가정하겠습니다. 그렇지 않으시다면 이 포스팅을 찾아서 읽고 계실 이유가 없겠지요. 뭐, 그것이 아니라면 최소한 소켓프로그래밍에 관심이 있어 어디에서 든지 배워 보고자 하시는 분들이겠지요. 따라서 소켓의 역사니, 어쩌고 귀찮은 이야기 들은 하지 않도록 하겠습니다.

간단 명료하게 시작하도록 하겠습니다.

소켓프로그램을 시작하기 위해서는 '소켓(socket)'이라는 것이 필요 합니다.

너무 당연한 말인가요?

일단 소켓이라는 것이 무엇인지에 대해서 먼저 알아보도록 하겠습니다. 전산학에 관련된 모든 정의를 내린다고 해도 과언이 아닐 정도로 정의를 많이 가지고 있는 RFC문서에 따르자면 아래와 같이 이야기 하고 있습니다.(see  RFC 147)

 A socket is defined to be the unique identification to or from which information is transmitted in the network....
 ..중략..
 A socket has been defined to be the identification of a port for machine to machine communication...
 ..생략..

위 내용을 간략하게 요약하면 인터넷 같은 네트워크 환경에서 통신을 하고자 할 때 통신의 종단점을 나타내는 것입니다. 예를 들어 여러분과 제가 각각 한 대의 컴퓨터를 가지고 통신을 하고자 한다고 가정 하도록 하겠습니다. 여러분은 제 컴퓨터의 주소가 적힌 소켓을 가지고 있어야 하고, 저는 여러분의 컴퓨터의 주소가 적힌 소켓을 가지고 있어야 합니다.

즉, 여러분이 가지고 계시는 컴퓨터와, 통신을 하고자하는 컴퓨터를 구분하고 위치를 알 수 있게 해주는 식별자 정도로 정의 할 수 있겠습니다. (원래라면 여기에서 주소와 포트에 관련된 이야기가 줄줄 따라 나와야 하지만 오늘은 socket 함수에 대해서 고찰 하는 시간이므로 자세한 이야기는 잠시 미뤄두도록 하겠습니다.)

이제 소켓이 무엇인지 대략이나마 감을 잡았습니다. 아직 감이 잘 안 오신다구요? 괜찬습니다. 저도 마찬가지 입니다. 하지만 괜찮습니다. 같이 공부하다 보면 천천히 알게 되겠지요.

소켓을 만들기 위해서는 socket 함수를 이용합니다.
#include <sys/socket.h>
int socket(int socket_family, int socket_type, int protocol); 

리눅스(혹은 유닉스)에서 소켓을 만드는 함수의 시놉시스는 위와 같습니다. 이 함수에 '적절한 파라메터'를 넘겨주게 되면 이 함수는 커널에게 요청하여 OS 내부에서 생성된 커널 객체, 즉 소켓 리소스를 가리키는 '파일 디스크립터(file descriptor)'라는 정수형를 값을 돌려 줍니다. 파일 디스크립터는 어딘가에 있는 커널 객체를 가리키는 일종의 번호표라고 생각하시면 됩니다. 사실 0번 부터 순차적으로 커지는 번호를 돌려 주는 것이기도 하구요.

그럼 위에서 말한 '적절한 파라메터'라는 것이 무엇인지 알아 볼 차례가 온 것 같군요. 그냥 소켓하나만 만들어 주면 될 것 같은데 뭘 이렇게 넘겨 줘야 하는 파라메터들이 많은 걸까요?

socket() 함수에 넘겨 주는 파라메터의 목적은 내가 원하는 종류의 소켓을 만들어 내는 것입니다.

네~말그대로 원하는 소켓을 만들기 위해 저 많은(?) 파라메터들이 필요 한 것입니다. TCP니 UDP니 SCTP니 하는 프로토콜들을 많이 들어 보셨을 겁니다. 뭐 못 들어 보셨어도 별 상관은 없습니다. 지금 당장 중요한 것은 아니니까요. 그냥 소켓에는 TCP 소켓, UDP 소켓, SCTP 소켓이 있구나..라는 정도만 알아 두시면 됩니다. 몇 가지 특이한 소켓들이 더 있긴 하지만 그 부분에 대해서는 특별히 포스팅 하나를 할애해서 따로 설명 하도록 하겠습니다.

이제 원하는 소켓을 만들기 위해 위의 파라메터들을 넘겨 줘야 한다는 것은 알았으나, 정확히 어떤 것을 넘겨 줘야 하는지는 아직 설명 하지 않았군요. 그럼 지금 부터 설명 하도록 하겠습니다.

socket_family라는 것은 어찌보면 '소켓의 가족'이라는 의미로 들릴 수도 있겠지만 그것 보다는 영역(domain) 정도로 생각하시면 될 듯 합니다. 그 영역이라는 것이 무엇인고 하니, 이 소켓이 IPv4의 주소 체계로 인식 되는 소켓인지, 아니면 새로 나온 IPv6로 인식 되는 소켓인지 그것도 아니면 Unix domain 소켓인지, 소켓이 사용되는 영역등으로 생각하시면 편하실 듯 합니다. 참고적으로 말하자면 방금 말씀드린 Unix domain 소켓이라는 것은 프로세스간 통신에 사용되는 소켓으로 이름은 Unix라고 달고 있지만 Unix뿐만 아니라 버클리 계열에도 구현 되어 있습니다. socket_family로 지정 될 수 있는 값들은 아래와 같습니다.

Name Purpose Man page
PF_UNIX, PF_LOCAL Local communication unix(7)
PF_INET IPv4 Internet protocols ip
(7)
PF_INET6 IPv6 Internet protocols           
PF_IPX IPX - Novell protocols  
PF_NETLINK Kernel user interface device netlink(7)
PF_X25 ITU-T X.25 / ISO-8208 protocol x25(7)
PF_AX25 Amateur radio AX.25 protocol  
PF_ATMPVC Access to raw ATM PVCs  
PF_APPLETALK Appletalk ddp(7)
PF_PACKET Low level packet interface packet(7)


 참으로 많은 종류의 값들이 정의 되어 있군요. 하지만 실망 하실 필요는 없습니다. 지금 글을 적고 있는 저도 저렇게 많은 종류가 있다고는 상상도하지 못했습니다. 하하하..같이 모른다고 기쁜 일은 아니라구요..네..그래도 지금 부터 알아가면 되겠지요. 이제 시작인데 너무 처음 부터 겁먹을 필요는 없습니다. 오늘 여기서 우리가 주의 깊게 봐야 할 부분은 노란색으로 하이라이트 처리 되어 있는 두 줄, 그것 중에서도 첫번째 것, "PF_INET"입니다. 네 바로 IPv4에서 사용할 소켓을 만들겠다라는 뜻입니다. 당연히 바로 밑에있는 'PF_INET6'는 IPv6를 위한 것이겠지요?
 "PF_X25"라는 다소 생소해 보이는 녀석들도 있는데, 이 프로토콜은 국가간 같은 대규모 망에서나 사용 될까 말까 할 정도의 프로토콜이라고 하니 미리 부터 저것을 어떻게 사용하지 하면서 골머리를 썩일 필요 는 없을 것 같습니다.
 참고로 위의 매크로들은 <sys/socket.h> 파일에 정의 되어 있습니다. 관심있으신 분들은 한번쯤 들려 보는 것도 괜찮을 것 같군요.

 socket_type은 그나마 좀 낫습니다. 왜냐구요? 몇 개 안되거든요.

 SOCK_STREAM

TCP 소켓 리턴 하도록 합니다. 여기서 TCP 소켓이 신뢰성 있고, 순서가 보장되며, conntected-base stream이며 쌍방향 통신을 제공한다..라는 말은 하지 않겠습니다.

SOCK_DGRAM

UDP 소켓을 리턴 하도록 합니다.

SOCK_SEQPACKET

 SCTP 소켓을 리턴 하도록 합니다.

SOCK_RAW

raw network 프로토콜에 억세스 할 수 있는 소켓을 리턴 합니다.

SOCK_RDM

Provides a reliable datagram layer that does not guarantee ordering.

SOCK_PACKET

Obsolete and should not be used in new programs; see packet(7).

역시 듣도 보도 못한 플래그들이 있긴 하지만 우리가 신경 써야 할 부분은 그리 많지 않습니다. TCP에 대해서 공부하고 있으니 "SOCK_STREAM"정도? 거기다 보너스로 UDP와 관련된 'SOCK_DGRAM'을 신경 쓸 수도 있겠지요.

대망의 마지막 protocol입니다.
뭔가 거창하게 이야기했지만 사실 대부분의 경우 0으로 지정하는 거의 사용되지 않는 인자입니다. 원래는 소켓에서 사용되는 특정 프로토콜(예를 들어 TCP 또는 UDP)을 지정하는 용도이지만 0으로 지정하면 socket_family 인자에 맞춰 알아서 셋팅 됩니다.

이상 socket 함수에 대해 알아 보았습니다. 반응이 괜찮다면 read/write에 대해서도 글을 써볼까 하네요.

유익한 글이었다면 공감(❤) 버튼 꾹!! 추가 문의 사항은 댓글로!!