Prev | Contents | Next

2 소켓이란 무엇인가?

여러분은 “소켓”이란 단어를 자주 들을 것입니다. 그리고 어쩌면 그것이 정확히 무슨 뜻인지 궁금하시겠지요. 그것은 표준 유닉스 파일 설명자를 통해서 다른 프로그램과 이야기하는 방법을 의미합니다.

무슨 말이냐고요?

좋습니다. 아마 어떤 유닉스 해커들이 “어으, 유닉스에선 모든 것이파일이야!” 라고 말하는 것을 들어보셨을 것입니다. 그들이 말하는 바는 유닉스 프로그램이 어떤 종류의 입출력을 하든, 파일 설명자에 읽거나 쓰는 방식으로 동작한다는 의미입니다. 파일 설명자는 단순히 열려있는 파일과 연관된 정수입니다. 그러나 (이 부분이 중요합니다.) 그 파일은 네트워크 연결이나 선입선출, 파이프, 터미널, 디스크에 있는 진짜 파일이나 다른 어떤 것이든 될 수 있습니다. 유닉스의 모든 것 은 파일입니다! 그러니 인터넷 너머의 다른 프로그램과 통신하고 싶다면 파일 설명자를 통해서 하는 것이 당연합니다.

“똑똑하시네요. 그래서 이 네트워크 통신을 위한 파일 설명자를 어디에서 구하죠?” 이라고 아마 지금 생각하실 듯 합니다. 답을 드리자면 socket() 시스템 루틴을 호출하면 된다는 겁니다. 그것은 소켓 설명자를 반환하고, 여러분은 특화된 send()recv() (man send, man recv) 소켓 함수를 써서 그 소켓을 통해 통신합니다.

“그런데 잠시만요!” 아마 다른 의문이 생길 것입니다. “그게 그냥 파일 설명자라면, 어째서 그냥 평범한 read()write() 함수를 사용해서 소켓 통신을 하면 안되나요?” 짧은 답은 “그래도 됩니다!”입니다. 긴 답은 “그래도 되지만, send()recv()이 데이터 전송을 더 많이 조정할 수 있게 해 줍니다”가 되겠습니다.

다음이 궁금하신가요? 세상에는 온갖 종류의 소켓이 있습니다. DARPA 인터넷 주소(인터넷 소켓), 로컬 노드의 경로(유닉스 소켓), CCITT X.25 주소(무시해도 상관없는 X.25주소), 그리고 여러분이 실행중인 유닉스의 종류에 따라 다른 많은 종류의 소켓들. 이 문서는 첫 번째 것에 대해서만 다룹니다. 바로 인터넷 소켓입니다.

2.1 두 종류의 인터넷 소켓

인터넷 소켓이 두 종류라니 무슨 소리냐고요? 사실 거짓말입니다. 더 많은 종류가 있습니다. 그러나 여러분을 겁주기가 싫었습니다. 여기서는 두 종류에 대해서만 이야기하겠습니다. 여러분에게 “Raw Socket”이라는 것이 있으며 그것이 아주 강력하고 한 번쯤 살펴보시길 권한다고 말하는 지금 이 문장을 제외하고 말입니다.

이쯤하고, 그 두 개의 종류가 무엇인지 이야기하자면 하나는 “Stream Socket(스트림 소켓)”이고 다른 하나는 “Datagram Socket(데이터그램 소켓)”입니다. 앞으로 이 둘을 각각 “SOCK_STREAM” 과 “SOCK_DGRAM”으로 칭하겠습니다. 데이터그램 소켓은 때때로 비연결형/비연결성 소켓이라고 불립니다. (그러나 그것도 정말로 필요하다면 connect() 함수를 사용할 수 있습니다. 아래의 connect()를 참고하세요.)

스트림 소켓은 신뢰성있는 양방향 연결 통신 스트림입니다. 이 소켓에 두 개의 아이템을 “1, 2”의 순서로 출력하면, 반대쪽 끝에 “1, 2”의 순서로 도착합니다. 또한 스트림소켓은 에러가 발생하지 않습니다. 이것은 정말로 확실한 내용이어서, 저는 다른 사람들이 이것에 대해서 반박한다면 귀를 막고 노래를 불러서라도 무시하겠습니다.

스트림 소켓의 사용처가 궁금한가요? telnet이나 ssh 응용프로그램에 대해서 들어보셨나요? 그것들이 스트림 소켓을 사용합니다. 여러분이 입력하시는 모든 문자가 입력하신 순서 그대로 도착해야 합니다. 또한, 웹브라우저가 쓰는 Hypertext Transfer Protocol (HTTP)도 스트림 소켓을 사용합니다. 실제로, 어떤 웹사이트의 80번 포트에 텔넷으로 연결한 후 “GET / HTTP/1.0”을 입력하고 엔터를 두 번 치면 HTML을 돌려줄 것입니다.

여러분이 telnet을 설치하지 않았고 설치하고 싶지 않거나, 설치된 telnet이 클라이언트에 연결하는 것에 대해 까다롭게 군다면 이 안내서는 telnet과 유사한 프로그램인 telnot7과 같이 제공됩니다. 이 안내서가 필요로 하는 일은 다 할 수 있을 것입니다. 텔넷이 사실은 명세된 네트워크 통신 프로토콜8이며, telnot 은 이 프로토콜을 전혀 구현하지 않는다는 사실을 기억하세요.

스트림 소켓이 어떻게 이렇게 수준높은 데이터 전송 품질을 달성할까요? 이를 위해 스트림 소켓은 “Transmission Control Protocol”혹은 “TCP” (TCP에 대한 지나치게 자세한 정보는 RFC 7939를 참고하세요) 라고 불리는 프로토콜을 사용합니다. TCP는 여러분의 데이터가 순서대로 도착하고 오류가 없음을 보장합니다. “TCP”를 “TCP/IP”의 반절로 이미 들어보셨을 것입니다. “IP”는 “Internet Protocol(인터넷 프로토콜)”의 약어입니다. (RFC 79110을 살펴보세요) IP는 주로 인터넷 라우팅을 맡으며 데이터 무결성에는 보통 책임이 없습니다.

좋습니다. 그럼 데이터그램 소켓은 뭘까요? 왜 비연결성일까요? 뭐가 다를까요? 왜 신뢰성이 없는 것일까요? 대답은 아래와 같습니다. 데이터그램을 전송하면 도착할 수도, 도착하지 않을 수도 있습니다. 도착은 하되 순서대로 도착하지 않을 수도 있습니다. 도착한다면, 패킷 안에 있는 데이터에는 에러가 없습니다.

데이터그램 소켓도 라우팅을 위해서 IP를 사용할 것입니다. 그러나 TCP를 사용하지는 않습니다. 데이터그램 소켓은 “User Datagram Protocol” 또는 “UDP”를 사용합니다. (RFC 76811를 참고하세요)

왜 비연결성인지에 대해서 간단히 말하자면 스트림 소켓과 달리 열린 연결을 유지할 필요가 없기 때문입니다. 패킷을 만들고, 목적지 정보를 담은 IP헤더를 붙이고 보냅니다. 연결은 필요없습니다. 데이터그램 소켓은 일반적으로 TCP 스택을 사용할 수 없거나 패킷 몇 개가 유실되어도 큰일이 나지는 않는 상황에서 쓰입니다. 몇몇 예제 프로그램은 다음과 같습니다. tftp (trivial file transfer protocol, FTP의 동생), dhcpcd (DHCP 클라이언트), 다중 사용자 게임, 오디오 스트리밍, 화상 회의 등등

“잠시만요! tftpdhcpcd는 하나의 호스트에서 다른 호스트로 이진 응용프로그램을 전송하기 위해 쓰이잖아요! 응용프로그램이 도착지에서 제대로 동작하길 바라면 데이터가 유실되면 안 되는 것 아닌가요? 데이터를 제대로 보내기 위해서 마법이라도 쓰나요?”

머글 여러분, tftp와 유사한 프로그램들은 UDP위에서 자신만의 프로토콜을 구현합니다. 예를 들어 tftp프로토콜은 그들이 보내는 모든 패킷에 대해서 수신자가 “잘 받았습니다”라고 말하는 패킷(“ACK” 패킷)을 돌려줄 것을 요구합니다. 원본 패킷의 송신자가 일정 시간, 가령 5초 안에 응답을 받지 못한다면 송신자는 ACK응답을 받을 때까지 패킷을 재전송합니다. 이 확인 절차는 아주 중요해서 신뢰할 수 있는 SOCK_DGRAM 응용프로그램을 만들 때 아주 중요합니다.

게임이나 오디오, 비디오같은 신뢰할 수 없는 응용프로그램의 경우 유실된 패킷을 그냥 무시하거나 혹은 똑똑하게 무마하려고 합니다. (퀘이크 사용자들은 이런 유실로 인한 영향을 전문 용어로 짜증나는 렉이라고 부릅니다. 여기에서 쓰인 “짜증나는” 은 아주 극단적인 욕설을 대체한 표현입니다.)

신뢰할 수 없는 기반 프로토콜을 왜 사용하는지 궁금한가요? 이유는 단 하나, 속도입니다. 발사 후 망각(fire-and-forget) 방식이 무엇이 안전하게 도착했는지 추적하고 데이터가 올바른 순서로 왔는지 등을 확인하는 것보다 빠릅니다. 대화 메시지를 보낸다면 TCP는 훌륭한 선택입니다. 게임 세상 안에 있는 각각의 사용자에 관한 초당 40번의 위치 정보 갱신을 전송한다면 한두 개의 정보가 유실되어도 상관없습니다. 그렇다면 UDP가 좋은 선택입니다.

2.2 저수준 넌센스와 네트워크 이론

프로토콜의 계층구조에 대해서 이야기했으니 네트워크가 실제로 어떻게 동작하는지 말씀드릴 차례입니다. SOCK_DGRAM패킷이 어떻게 만들어지는지 약간의 예제를 보여드리겠습니다. 실용적으로는 이 절을 생략해도 좋습니다. 그러나 좋은 배경지식입니다.

데이터 캡슐화(Data Encapsulation).

데이터 캡슐화에 대해 배울 차례입니다. 이것은 아주 중요합니다. 너무 중요해서 치코 캘리포니아 주립대에서 네트워크 수업을 듣는다면 이것에 대해 배우게 될 수도 있습니다. 간단히 말하자면 이렇습니다. 패킷이 태어나면 패킷은 첫 번째 프로토콜(예를 들어 TFTP 프로토콜)에 의해 헤더로 감싸집니다(“캡슐화”) (때때로 푸터로도 감싸집니다). 그리고 (TFP의 헤더가 포함되는) 전체가 다시 다음 프로토콜에 의해 감싸집니다 (예를 들어 UDP). 그리고 다시 IP로 감싸지고, 또 다시 하드웨어(물리) 계층(예를 들어 이더넷Ethernet)에 의해 최종적인 프로토콜로 감싸집니다.

다른 컴퓨터가 패킷을 받으면 하드웨어는 이더넷 헤더를 벗겨내고, 커널이 IP와 UDP헤더를 벗겨냅니다. 그리고 TFTP프로그램이 TFTP헤더를 벗겨내고, 마침내 데이터를 가지게 됩니다.

드디어 악명높은 계층화 네트워크 모델(Layered Network Model) 에 대해서 이야기할 수 있습니다. 이 네트워크 모델은 네트워크 기능의 계(system) 를 묘사하며 다른 모델에 비해서 많은 장점을 가지고 있습니다. 예를 들어 여러분은 물리적으로 데이터가 어떻게 전송되는지(직렬통신(Serial), Thin Ethernet(얇은 동축케이블을 쓰는 이더넷의 변형), AUI(Attachment Unit Interface), 등등)(역자 주 : 여기에 언급되는 물리적 통신 단자들은 대개 현재는 특수한 산업현장이 아니면 쓰이지 않습니다. 여러분이 이런 것에 대해서 모르신다고 해도 전혀 지장이 없다는 의미입니다.)에 대해서 전혀 신경쓰지 않고 소켓 프로그램을 완전히 똑같은 모습으로 짤 수 있습니다. 그 이유는 저수준에 있는 프로그램들이 그것을 자동으로 처리해주기 때문입니다. 실제 네트워크 하드웨어와 망 구성방식(topology)는 소켓 프로그래머에게 투명(역자 주 : 알 필요가 없거나 알 수 없음)합니다.

길게 말하지 않고 이제 전체 모델의 계층을 제시하겠습니다. 네트워크 과목 시험을 위해서 이것을 기억하세요.

물리 계층은 하드웨어입니다(직렬통신, 이더넷 등). 응용 계층은 여러분이 상상할 수 있는 한 최대한 물리 계층에서 먼 것입니다. 사용자가 실제로 네트워크와 상호작용 하는 부분을 의미합니다.

사실 이 모델은 너무나 일반적이어서 정말로 원한다면 자동차 정비 안내서에도 쓸 수 있을 것입니다. 유닉스와 좀 더 일치하는 계층화 모델은 이렇습니다.

이 시점까지 오면 여러분은 아마도 이 계층들이 원본 데이터의 캡슐화에 어떻게 대응하는지 아실 수 있을 듯 합니다.

간단한 패킷을 만들기 위해서 얼마나 많은 일이 일어나는지 아시겠나요? 그리고 이것을 패킷 헤더에 적기 위해서 “cat”명령으로 하나하나 직접 적어야 합니다! 농담입니다. 스트림 소켓을 위해서 할 일은 그저 send() 로 데이터를 보내는 것 뿐입니다. 데이터그램 소켓을 위해서 할 일은 여러분이 원하는 방식으로 패킷을 캡슐화하고 sendto() 로 내보내는 일 뿐입니다. 커널이 여러분을 위해서 전송 계층과 인터넷 계층을 만들어주고 하드웨어가 네트워크 접근 계층을 만들어줄 것입니다. 현대 기술은 정말 멋지지요!

네트워크 이론에 대한 우리의 짧은 공부는 이렇게 끝납니다. 아, 라우팅에 대해서 말씀드리는 것을 잊었습니다. 그러나 라우팅에 대해서는 아무것도 다루지 않을 생각입니다. 라우터(router)가 IP헤더에 이르기까지 패킷을 까고, 라우팅 테이블 (routing table)을 조회하고, 어쩌고 저쩌고등에 대한 내용은 하나도 이야기하지 않을 것입니다. 정말로 진짜로 알고싶다면 IP RFC12을 참고하세요. 평생 모르고 살아도 문제는 없습니다.


Prev | Contents | Next