CS/Network

[Chapter 12] 소켓을 이용한 네트워크 프로그래밍 (소켓의 주소 체계)

devrabbit22 2025. 2. 17. 15:58

소켓은 자체에 어떤 기능이 있는 것이 아니고, 운영 체제에서 제공하는 통신 프로토콜을 편리하게 사용할 수 있도록 도와주는 역할을 한다. 따라서 소켓 주소는 사용하는 프로토콜의 종류에 다라 여러 형태의 주소 체계를 지원한다.

소켓의 주소 체계

소켓은 프로토콜 종류에 따라 다양한 방식으로 주소를 부여할 수 있다. 일반 프로그래밍 환경에는 AF_UNIX와 AF_INET의 소켓 주소 체계를 많이 사용한다.

유닉스 주소 체계

AF_UNIX로 표시되는 유닉스 주소 체계는 하나의 호스트 내부에서 실행되는 프로세스 사이의 통신을 지원하며, 사용하는 주소 체계는 파일 시스템의 경로명을 기반으로 한다.

ex)유닉스 주소체계를 지원하는 sockaddr_un 구조체의 예시, 두 개의 필드를 사용한다. sun_family 필드는 유닉스 주소 체계를 의미하는 AF_UNIX 값을 갖는다. sun_path 필드에는 소켓을 구분하는 주소를 표시하기 위해 파일 시스템의 경로명을 기록한다.

struct sockaddr_un {
	short sun_family; // AF_UNIX
	char sun_path[108]; // pathname
};

인터넷 주소 체계

인터넷 주소 체계는 하나의 호스트 내부에서 실행되는 프로세스 사이의 통신을 지원하는 유닉스 주소 체계와 달리, 서로 다른 호스트에서 실행되는 프로세스 사이의 통신을 지원하며 AF_INET로 표시한다.

AF_INET 방식은 소켓이 생성되는 호스트의 IP주소와 포트 번호를 조합하여 소켓 주소를 표현한다. 

ex) 인터넷 주소 체계를 지원하는 sockaddr_in 구조체의 예시, 모두 4개의 필드를 사용한다. sin_family 필드는 인터넷 주소 체계를 의미하는 AF_INET 값을 갖는다. sin_zero 필드는 사용되지 않으며, sin_addr과 sin_port 필드에 주소를 표시한다. sin_addr 필드에는 호스트의 IP 주소를, sin_port 필드에는 포트 번호를 기록한다. IP 주소가 기록되는 sin_addr 필드는 in_addr 구조체에 의해 크기가 332비트인 u_long 형의 s_addr 필드로 재지정된다.

struct sockaddr_in {
	short sin_family; // AF_INET
	u_short sin_port; // 포트 번호
	struct in_addr sin_addr; // IP 주소
	char sin_zero[8];	// 채우기
};

struct in_addr {
	u_long s_addr;
};

통합 주소 체계

소켓의 주소 체계는 사용하는 프로토콜에 따라 달라지므로 운영체제에서 제공하는 통신 프로토콜의 수가 증가하면 주소 체계의 표현 방식도 증가한다.

소켓 주소는 소켓 시스템 콜을 통해 사용되는데, 의미는 같으나 형식이 다른 여러 구조체를 함수 매개변수 하나로 수용하는 것은 문법적으로 불가능하다. 따라서 여러 소켓 구조체를 통합해 일반 구조체 하나로 정의할 필요가 있다. 다음과 같이 sockaddr이라는 공통 주소 체계를 지원하는 구조체를 사용해 소켓 주소 표현 방법을 정의할 수 있다. 이 구조체는 단순히 프로그래밍 환경에서 문법적인 측면만 고려해 정의된 것이며 sockaddr 구조체에 의해 할당된 공간은, 유닉스나 인터넷 주소 체계 같은 다른 주소 체계에서 필요한 공간보다 커야 한다.

struct sockaddr {
	u_short sa_family; // AF_UNIX, AF_INET, ... ...
	char sa_data[14];
};

ex) 인터넷 주소 체계를 이용해 소켓 프로그래밍을 하는 경우에 소켓 변수는 다음과 같이 sockaddr_in 구조체를 사용한다. 이후 주소를 보관하는 addr 변수에는 인터넷 주소 체계에서 사용하는 IP주소와 포트 번호 값을 지정한다. 그런데 맨 아래에 있는 소켓 관련 시스템 콜bind()는 모든 통신 프로토콜에서 공통으로 사용한다. 따라서 주소 값이 입력되는 두 번째 매개변수를 특정 주소 체계의 구조체로 고정하여 정의할 수 없다. 에시와 같이 공통 주소 체계인 sockaddr 구조체로 형변환하여 문법의 통일성을 유지해야 한다.

struct sockaddr_in addr; // 인터넷 주소 체계로 변수 선언
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = hton1(INADDR_ANY); // IP 주소
addr.sin_port = htons(5010); // 포트 번호
bind(socet, (struct sockaddr *)&addr, sizeof(addr));

결과적으로 bind() 함수의 두 번째 매개변수는 struct sockaddr 형의 포인터 변수만 오도록 정의되었으나, 실제 사용되는 변수는 각 프로토콜에서 정의된 주소 체계로 선언된다. 예시에서는 addr 변수를 통해 소켓이 인터넷 주소 체계인 sockaddr_in 구조체로 생성되지만, 시스템 콜에서는 문법적으로 sockaddr 구조로 형 변환하여 표현한다.

소켓의 서비스

  • SOCK_STREAM, SOCK_DGRAM, SOCK_RAW로 분류할 수 있다.
  • SOCK_STREAM은 연결형 서비스에서, SOCK_DGRAM은 비연결형 서비스에서 사용한다. SOCK_RAW는 일반 네트워크 응용 프로그램 개발에서는 자주 사용되지 않고 IP프로토콜을 직접 사용해 통신할 때 사용한다.

소켓의 기본 함수

소켓 시스템 콜을 이용해 네트워크 프로그래밍을 할 때는 다음 7개의 기본 함수가 사용된다.

  1. socket(int domain, int type, int protocol)
    • socket() 함수는 매개변수로 지정한 유형에 따라 소켓을 생성한다. 시스템 콜이 성공적으로 실행되어 소켓이 만들어지면 해당 소켓의 디스크립터를 반환하고, 이 값은 파일 I/O의 디스크립터와 똑같은 방식으로 사용한다.
  2. bind(int s, const struct sockaddr *name, socklen_t *namelen)
    • bind()함수는 매개변수로 지정한 유형에 따라 소켓을 생성한다. 시스템 콜이 성공적으로 실행되어 소켓이 만들어지면 해당 소켓의 디스크립터를 반환하고, 이 값은 파일 I/O의 디스크립터와 똑같은 방식으로 사용한다.
  3. listen(int s, int backlog)
    • listen()함수는 첫 번째 매개변수로 표시한 소켓을 활성화 하는데, 보통 서버 프로세스에서 실행된다. 시스템에서 연결을 거부하지 않고 대기할 수 있는 연결 설정 요구의 최대 수를 지정한다.
  4. accept(int s, struct sockaddr *addr, socklen_t *addrlen)
    • accept() 함수는 보통 서버 프로세스에서 실행되며, 첫 번째 매개변수로 지정한 소켓에서 클라이언트의 연결 요구가 들어올 때까지 대기한다. 임의의 클라이언트로부터 연결 설정 요구가 발생하면 둘 사이에 연결이 설정되고, 서버에 새로운 소켓이 자동으로 생성된다. 새로 생성된 소켓의 디스크립터는 반환 값 형태로 전달된다. 클라이언트의 연결 요구가 없으면 서버는 accept() 함수에서 대기한다.
  5. connect(int s, const struct sockaddr *name, socklen_t namelen)
    • connect() 함수는 클라이언트 프로세스에서 사용하며, 두 번째 매개변수 name이 가리키는 서버와 연결 설정을 시도한다. 해당 주소의 서버가 존재하지 않으면 오류 처리되고, 서버가 연결 대기중이면 연결이 설정된다.
  6. send(int s, const void *msg, size_t len, int flags)
    • send() 함수는 연결형 서비스를 제공하는 환경에서 데이터를 전송하는 역할을 한다. 즉, 첫 번째 매개변수 s로 표시한 소켓을 통해 상대방 프로세스에 두 번째 매개변수 msg에 보관된 데이터를 전송한다.
  7. recv(int s, void *buf, size_t len, int flags)
    • recv() 함수는 연결형 서비스에서 데이터를 수신하는 역할을 한다. 첫 번째 매개변수 s로 표시되는 소켓을 통해 데이터를 수신하고, 수신한 데이터를 두 번째 매개변수 buf에 보관한다.

Reference 

쉽게 배우는 데이터 통신과 컴퓨터 네트워크