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

·2023년 10월 29일
0

[프로토콜의 정의]

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

[소켓의 생성]

  • 소켓을 생성하기 위해서는 socket이란 함수를 사용해야 함
  • socket 함수는 호출 시 시스템 내부적으로 소켓을 생성하고 그 소켓을 조작하기 위해 필요한 파일 디스크립터를 리턴함
    • 시스템 내부적으로 소켓을 생성한다?
      → 호스트가 통신을 하기 위해 필요한 리소스를 할당하는 것을 의미
#include <sys/types.h>
#include <sys/socket.h>
    
int socket(int domain, int type, int protocol);
    
// 성공 시 파일 디스크립터, 실패 시 -1을 리턴

// domain : 생성할 소켓이 통신을 하기 위해 사용할 프로토콜 체계를 설정
// type : 소켓이 데이터를 전송하는데 있어서, 사용하게 되는 전송 타입을 설정
// protocol : 두 호스트간에 통신을 하는데 있어서 특정 프로토콜을 지정하기 위해 사용

[프로토콜 체계]

  • socket 함수의 첫 번째 인자 (domain)
    • 소켓을 생성 할 때 환경을 고려하여 프로토콜 체계를 지정해 주면 그 환경에서 사용 가능한 소켓이 됨
      → 소켓은 모든 프로토콜을 수용할 수 있음, “소켓은 프로토콜에 독립적이다.” 라고도 표현

      [프로토콜 체계의 종류와 설명]
      종류설명
      PF_INETIPv4 인터넷 프로토콜
      PF_INET6IPv6 인터넷 프로토콜
      PF_LOCALLocal 통신을 위한 UNIX 프로토콜
      PF_PACKETLow Level Socket을 위한 인터페이스
      PF_IPXIPX 노벨 프로토콜

[소켓의 타입]

  • socket 함수의 두 번째 인자 (type)
    • 데이터 전송 타입을 의미
  • 프로토콜의 체계가 정해졌다고해서 데이터 전송 방법까지 완전히 결정된 것은 아님 → 프로토콜 체계 안에서도 데이터를 전송하는 방법이 둘 이상 존재할 수 있음

[대표적인 데이터 전송 방식 두 가지]

(1) SOCK_STREAM : 신뢰성 있는 순차적인 바이트 기반의 연결 지향 전송 타입

  • 에러나 데이터의 손실 없이 무사히 전달됨
    • 호스트 대 호스트의 연결은 1:1이어야 함
  • 전송하는 순서대로 데이터가 전달됨
  • 전송되는 데이터의 경계가 존재하지 않음
    • 두 번의 write 함수 호출을 통해 데이터를 전송했다 하더라도, 수신측 호스트의 버퍼가 넉넉하다면 한 번의 read 함수 호출을 통해서 모든 데이터 수신 가능
    • 반대로 한 번의 write로 보낸 데이터를 여러번의 read 함수 호출을 통해서 나누어 수신 가능

(2) SOCK_DGRAM : 비연결 지향 전송 타입

  • 전송되는 순서에 상관없이 가장 빠른 전송 지향
  • 전송되는 데이터는 손실될 수도 있고 에러가 발생할 수도 있음
  • 전송되는 데이터의 경계가 존재함
  • 한 번에 전송되는 데이터의 크기는 제한됨
    • 크기가 크다면 적절히 데이터를 나눠야 함

[프로토콜의 선택]

  • socket 함수의 세 번째 인자(protocol)
  • 호스트 대 호스트가 사용할 프로토콜을 설정하기 위해 사용됨
    • 프토토콜 체계가 PF_INET인 경우 다음과 같은 값이 올 수 있음
      종류설명
      IPPROTO_TCPTCP를 기반으로 하는 소켓 생성
      IPPROTO_UDPUDP를 기반으로 하는 소켓 생성

[세 번째 인자는 왜 필요할까?]

프로토콜 체계가 PF_INET고 소켓 타입이 SOCK_STREAM이면 당연히 인터넷 기반 연결 지향 소켓을 생성하는 거 아닌가? 왜 세 번째 인자 값으로 IPPROTO_TCP를 넣어줘야 하지??

→ 사실 첫 번째와 두 번째 인자를 통해서도 충분히 원하는 소켓의 정보를 전달한 것이기 때문에 세 번째 인자 값에다가 0을 넣어줘도 알아서 우리가 원하는 소켓을 생성해 줌

그렇다면 왜 세 번째 인자가 존재할까?

→ 하나의 프로토콜 체계 안에서 데이터 전송 타입까지 같으면서도 최종적으로 통신하는 형태가 다른 경우가 있음. 그 때 프로토콜을 조금 더 구체화하기 위해 사용됨

(RAW_SOCKET을 생성하는 경우 세 번째 인자가 유용하게 사용됨 → 이 책에서는 다루지 않음)

(추가) RAW_SOCKET은 뭘까?

  • 네트워크 계층, 전송 계층의 헤더 정보를 직접 제어 가능한 socket
  • root 권한에서만 사용 가능
  • 네트워크 계층으로 전송되는 모든 패킷을 모니터링 및 감지 하는 데 사용 됨 → 대표적으로 보안 프로그램 구현 시 사용

[소켓 생성하기]

#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>

void error_handling(char* message);

int main(int argc, char** argv)
{
	int tcp_socket;
	int udp_socket;

	// 연결 지향 TCP 소켓 생성
	tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	if(tcp_socket == -1)
		error_handling("socket() error");

	udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if(udp_socket == -1)
		error_handling("socket() error");

	printf("생성된 TCP 소켓의 파일 디스크립터 : %d \n", tcp_socket);
	printf("생성된 UDP 소켓의 파일 디스크립터 : %d \n", udp_socket);

	close(tcp_socket);
	close(udp_socket);
	return 0;
}

void error_handling(char* message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

[실행 결과]

0개의 댓글