layered

2 소켓의 타입과 프로토콜의 설정 본문

네트워크/열혈 TCP IP 소켓 프로그래밍

2 소켓의 타입과 프로토콜의 설정

스윗푸들 2023. 4. 28. 23:44

프로토콜 Protocol


컴퓨터 상호간의 대화에 필요한 통신규약.

이렇게 말하면 조금 모호한 면이 있을 것이다. 간단하게 다음과 같은 상황이 있다고 생각해 보자.

 

컴퓨터들이 서로 통신을 하려고 한다.

 

몇 가지 물음표가 떠오를 것이다.

 

  • What is communicated
  • How it is communicated
  • When it is communicated

이런 것들을 상호간에 정하는 게 바로 프로토콜이다!

 

이제 소켓을 생성하는 함수를 다시 살펴보자.

 

int socket(int domain, int type, int protocol);
SOCKET socket(int af, int type, int procotol);

 

domain, af

소켓이 사용할 프로토콜 체계(Protocol Family) 정보를 전달하는 부분이다.

간단하게 말하면 프로토콜의 분류를 나타낸다고 보면 된다.

여기에서 넘겨 준 프로토콜 체계에 따라, 최종 프로토콜의 정보를 나타내는 세 번째 인자가 결정된다.

 

이름 프로토콜 체계
PF_INET IPv4 인터넷 프로토콜 체계
PF_INET6 IPv6 인터넷 프로토콜 체계
PF_LOCAL 로컬 통신을 위한 UNIX 프로토콜 체계
PF_PACKET Low Level 소켓을 위한 프로토콜 체계
PF_IPX IPX 노벨 프로토콜 체계

 

그런데 윈속의 소켓 생성 함수를 보면 어쩐지 PF와는 조금 다른데 이는 주소 체계로, 프로토콜 체계처럼 주소의 분류를 나타내는 것이다. 그런데 또 헤더 파일을 보면 PF와 AF는 같은 값을 가진다.

 

#define PF_UNSPEC       AF_UNSPEC
#define PF_UNIX         AF_UNIX
#define PF_INET         AF_INET
#define PF_IPX          AF_IPX
#define PF_INET6        AF_INET6
// 등등

 

그래서 둘을 혼용해서 쓰는 건 실질적으로는 문제가 없지만, 의미적으로 구분해서 쓰는 게 좋다고 한다.

프로토콜 체계는 소켓을 생성할 때, 주소 체계는 주소 구조체를 초기화할 때.

 

메모

찾아 보니 소켓 인터페이스의 원래 개념은 하나의 프로토콜 체계가 여러 개의 주소를 가질 수 있다는 것이어서, 주소 체계를 따로 구분해 두고 사용하도록 했다고 한다. 그런데 막상 보니 그런 경우가 딱히 없고, 실질적인 정의도 같다 보니 섞여서 쓰이고 있는 것이라고 한다.

사실 이해가 잘 안 되어서 그냥 써 두기만 했다... 일단은 프로토콜 체계를 파라미터로 넘겨 준다는 것만 기억하고 넘어가야겠다.

 

type

소켓의 타입은 소켓의 데이터 전송 방식을 의미하며, 네트워크 프로토콜의 종류에 따라 달라진다.

대표적으로 두 가지가 있다.

 

1 SOCK_STREAM

"저기... 데이터 좀 보내도 되나요?"

연결지향형 소켓으로, 경로를 확보해 두고 수신자의 상황을 판단해 가면서 데이터를 전송한다.

따라서 전송되는 데이터의 경계가 없고 신뢰성을 보장하며, 전송한 순서대로 데이터가 수신된다.

 

2 SOCK_DGRAM

"데이터 보낼게요!"

비 연결지향형 소켓으로, 그냥 냅다 보내기 때문에 속도는 빠르지만 손실되거나 뒤죽박죽 전송될 우려가 있다.

또한 한번에 보낼 수 있는 데이터의 크기가 제한되어 있어서 데이터의 경계가 존재한다.

 

주로 다루는 것이 인터넷 프로토콜임을 생각할 때, 위의 소켓 타입으로 결정되는 프로토콜은 각각 TCP와 UDP이다.

 

여기까지 종합해 보면 첫 번째 파라미터인 PF를 통해 프로토콜의 분류를 설정하고, 두 번째 파라미터인 type으로는 그 분류 내에서 사용할 프로토콜을 지정하는 것이라고 할 수 있다.

 

protocol

사용할 프로토콜을 지정한다. 하나의 프로토콜 체계 안에 데이터의 전송 방식(= 소켓 타입)이 동일한 프로토콜이 여러 개 있을 경우, 앞선 두 개의 파라미터로는 구분할 수 없기 때문이다.

TCP나 UDP의 경우는 상관이 없기 때문에 그냥 0을 넣기도 하지만, 굳이 명시하고자 한다면 IPPROTO_TCP나 IPPROTO_UDP를 사용하면 된다.

 

간단한 소켓 생성 코드!

 

int main() {
	WSADATA wsadata;
	if (WSAStartup(MAKEWORD(2, 2), &wsadata))
		return 1;
	printf("윈속 초기화!\n");

	SOCKET sock = socket(PF_INET, SOCK_STREAM, 0);
	if (sock == INVALID_SOCKET)
		return 1;
	printf("소켓 생성!\n");

	closesocket(sock);
	WSACleanup();
	return 0;
}