Computer >> 컴퓨터 >  >> 프로그래밍 >> C 프로그래밍

C 언어로 구현하는 IPv6 소켓 주소: 단계별 완벽 가이드

C 언어로 구현하는 IPv6 소켓 주소: 단계별 완벽 가이드

IPv4 주소는 이미 누구나 익숙하게 알고 있는 개념입니다. 하지만 IPv4 주소가 사실상 고갈된 지금, 더 넓은 주소 공간을 제공하기 위해 IPv6가 도입되었습니다.

이 글에서는 C 언어에서 소켓을 위한 IPv6 주소를 구현하는 방법을 단계별로 살펴보겠습니다. 소켓 프로그래밍에서 IPv6 주소를 올바르게 이해하고 구현하면 IPv6 지원 네트워크에서 원활한 통신이 가능해지며, 진화하는 인터넷 환경과의 호환성도 함께 확보할 수 있습니다.

IPv6 주소란 무엇인가?

IPv6 주소는 인터넷 프로토콜 버전 6(IPv6)의 핵심 요소로, 네트워크에 연결된 장치를 식별하고 위치를 파악하는 데 매우 중요한 역할을 합니다. IPv4 주소 고갈 문제를 극복하고 훨씬 큰 주소 공간을 제공하기 위해 등장한 IPv6 주소는 128비트 숫자이며, 이를 통해 총 2^128개의 고유한 주소를 표현할 수 있습니다.

IPv6 주소의 기본 구조는 다음과 같습니다.

aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa

여기서 각 'a'는 0000부터 FFFF까지 범위의 16진수 4자리를 나타냅니다.

IPv6 주소 표기 규칙

IPv6 주소 표기에서는 16비트 블록 내의 선행 0(leading zero)을 생략할 수 있습니다. 예를 들어 2001:0DB8:0000:0000:0000:0000:0000:0001 주소는 2001:DB8::1로 축약하여 쓸 수 있습니다. '::' 표기법을 사용하면 0이 길게 반복되는 주소를 간결하게 표현할 수 있습니다.

다만 '::'가 여러 번 등록될 경우 모호성이 발생할 수 있으므로 주의해야 합니다. 이런 상황에서는 명확성을 위해 주소를 완전히 확장하여 표기하는 것이 좋습니다.

또한 IPv6 주소는 대소문자를 구분하지 않지만, 일관성을 위해 소문자를 사용하는 것이 관례입니다. IPv6 주소는 네트워크 인터페이스 식별, 패킷 라우팅, 장치 간 통신 등 다양한 목적으로 활용되며, 수동으로 할당하거나 DHCPv6 같은 프로토콜을 통해 자동으로 할당됩니다.

C 언어에서 소켓용 IPv6 주소 구현 절차

C 언어에서 소켓에 IPv6 주소를 구현하는 과정은 다음 단계로 정리할 수 있습니다.

  • 헤더 포함: 소켓 프로그래밍에 필요한 구조체와 함수를 제공하는 헤더 파일들을 먼저 포함시킵니다.
  • 소켓 생성: socket() 함수로 IPv6 소켓을 생성합니다. 이때 도메인은 AF_INET6로 지정하고, 타입은 TCP라면 SOCK_STREAM, UDP라면 SOCK_DGRAM을 사용합니다.
  • 소켓 바인드: bind() 함수를 사용해 소켓을 특정 IPv6 주소와 포트에 연결합니다. 이때 struct sockaddr_in6 구조체를 생성하여 필요한 정보를 담습니다.
  • 연결 대기: listen() 함수를 호출하여 들어오는 연결 요청을 받을 준비를 합니다.
  • 연결 수락: accept() 함수로 바인딩된 소켓에서 들어오는 연결을 수락합니다. 이 함수는 새로운 소켓 파일 디스크립터를 반환합니다.

예제 코드 1: 소켓용 IPv6 주소 구현하기

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define PORT 7070
#define BACKLOG 5

int main()
{
    int server_fd, new_socket;
    struct sockaddr_in6 server_addr, client_addr;
    socklen_t client_addr_len;

    // IPv6 소켓 생성
    server_fd = socket(AF_INET6, SOCK_STREAM, 0);
    if (server_fd == -1) {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }

    // 소켓 바인드
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin6_family = AF_INET6;
    server_addr.sin6_port = htons(PORT);
    server_addr.sin6_addr = in6addr_any;
    if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
        perror("Socket bind failed");
        exit(EXIT_FAILURE);
    }

    printf("Listening for connections on IPv6 address ...\n");

    // 들어오는 연결 대기
    if (listen(server_fd, BACKLOG) == -1) {
        perror("Socket listen failed");
        exit(EXIT_FAILURE);
    }

    printf("Waiting for incoming connections ...\n");

    // 연결 수락
    client_addr_len = sizeof(client_addr);
    new_socket = accept(server_fd, (struct sockaddr*)&client_addr, &client_addr_len);
    if (new_socket == -1) {
        perror("Socket accept failed");
        exit(EXIT_FAILURE);
    }

    printf("Connection successful on IPv6 address! \n");

    // 클라이언트 IPv6 주소 변환 및 출력
    char client_ip_str[INET6_ADDRSTRLEN];
    inet_ntop(AF_INET6, &(client_addr.sin6_addr), client_ip_str, INET6_ADDRSTRLEN);
    printf("Connected client IP: %s\n", client_ip_str);

    // 소켓 종료
    close(new_socket);
    close(server_fd);

    return 0;
}

실행 결과

$ gcc srr.c -o srr
$ ./srr
Listening for connections on IPv6 address ...
Waiting for incoming connections ...

코드 설명

이 예제에서는 먼저 IPv6 소켓을 생성하고 지정된 포트에 바인드한 뒤, 들어오는 연결을 대기합니다. 프로그램은 연결 대기 중임을 알리는 메시지를 차례로 출력하며, 클라이언트가 성공적으로 접속하면 연결 완료 메시지와 함께 해당 클라이언트의 IPv6 주소를 화면에 표시합니다. 마지막으로 열려 있던 모든 소켓을 닫으며 프로그램을 종료합니다. 이렇게 구현된 서버는 IPv6 네트워크를 통해 클라이언트와 통신할 수 있습니다.

참고로 in6addr_any를 사용하면 시스템의 모든 IPv6 인터페이스에서 들어오는 연결을 받을 수 있으며, inet_ntop() 함수는 바이너리 형태의 IPv6 주소를 사람이 읽을 수 있는 문자열로 변환하는 데 사용됩니다.

마무리

C 언어에서 소켓에 IPv6 주소를 구현하는 것은 IPv6 지원 네트워크에서의 통신을 가능하게 하는 핵심 작업입니다. 이번 글에서는 IPv6 소켓 생성부터 특정 주소와 포트에 대한 바인드, listen()을 통한 연결 대기, accept()를 통한 연결 수락, 그리고 클라이언트 IPv6 주소 출력까지 전체 흐름을 살펴보았습니다. 위 단계를 차근차근 따라 하고 적절한 함수와 구조체를 활용한다면, C 언어에서도 IPv6 주소 처리를 손쉽게 구현할 수 있습니다.

저자 소개

C 언어로 구현하는 IPv6 소켓 주소: 단계별 완벽 가이드

Bamdeb Ghosh

Bamdeb Ghosh는 무선 네트워킹 분야에서 오랜 실무 경험을 쌓아온 전문가입니다. 유선 및 무선 네트워크 환경에서 Wireshark 패킷 분석을 전문으로 하며, Android, 블루투스, 리눅스 명령어, Python에 대한 폭넓은 지식을 보유하고 있습니다. 개인 사이트: wifisharks.com