728x90
반응형

IP주소 변환

네트워크 프로그램에서 IP 주소는 4바이트 정수(IPV4)로 사용되지만 사람ㄷ르은 IP 주소를 문자열로 확인하고 이해는 것이 편하므로 서로간의 변환이 필요하게 되고 이런 변환을 위한 함수가 inet_addr()과 inet_ntoa() 입니다.

 

다음은 정수와 문자열 IP를 변환하는 간단한 예제입니다.

#include <winsock2.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
	WSADATA wsa;
	
    if(WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
    {
        printf("윈도우 소켓 초기화 실패!\n");
	return -1;
    }

	// 문자열 주소 출력
	char *ipaddr = "230.200.12.5";
	printf("IP 문자열 주소 : %s\n", ipaddr);

	// 문자열 주소를 4byte 정수로 변환
	printf("IP 문자열 주소 = > 정수 = 0x%08X\n", inet_addr(ipaddr));

	// 4byte 정수를 문자열 주소로 변환
	IN_ADDR in_addr;
	in_addr.s_addr = inet_addr(ipaddr);
	printf("IP 정수 => 문자열 주소 = %s\n", inet_ntoa(in_addr));

	WSACleanup();
	return 0;
}

 

  • inet_addr() 함수는 문자열 형태의 IP 주소를 바이트 정렬된 4바이트 정수로 변환합니다.
  • inet_ntoa() 함수는 4바이트 정수를 문자열 형태의 IP 주소로 변환합니다.
  • IN_ADDR 구조체는 다음과 같이 정의되어 IP 주소를 1바이트 형태나 2바이트 형태 , 4바이트 형태의 정수로 사용하기 쉽도록 정의된 구조체입니다.
typedef struct in_addr {
        union {
                struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
                struct { USHORT s_w1,s_w2; } S_un_w;
                ULONG S_addr;
        } S_un;
#define s_addr  S_un.S_addr /* can be used for most tcp & ip code */
#define s_host  S_un.S_un_b.s_b2    // host on imp
#define s_net   S_un.S_un_b.s_b1    // network
#define s_imp   S_un.S_un_w.s_w2    // imp
#define s_impno S_un.S_un_b.s_b4    // imp #
#define s_lh    S_un.S_un_b.s_b3    // logical host
} IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;

 

바이트 정렬

데이터를 메모리에 저장하는 표준 방식은 크게 두 가지입니다. 첫 번째는 리틀 엔디안(little-endian)은 작은 주소에 데이터의 끝 값부터 저장하며 두 번째 빅 엔디안(big-endian)은 큰 주소에 데이터의 끝 값부터 저장하는 방식입니다. 하나의 시스템에서 프로그램 한다면 문제가 없겠지만 네트워크 프로그램처럼 서로 다른 두 시스템에서 데이터를 주고 받아야 한다면 데이터 저장 방식 때문에 문제가 될 수 있습니다. 그러다 보니 소켓 프로그램에서 네트워크의 데이터 표준 방식은 빅 엔디안을 사용하자고 약속되어 있으며 IP와 포트 번호를 모두 빅 엔디안 방식으로 설정하고 이것을 네트워크 바이트 정렬이라고 합니다. 상대적으로 시스템 고유의 바이트 정렬 방식을 호스트 바이트 정렬이라 합니다.

 

리틀 엔디안과 빅엔디안에 4바이트 0x12345678이 저장되는 방식

다음 예제는 바이트 정렬에 사용되는 네 함수를 정리한 예제입니다.

#include <winsock2.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
    WSADATA wsa;
    if(WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
    {
        printf("윈도우 소켓 초기화 실패!\n");
		return -1;
    }

    unsigned short us = 0x1234;
    unsigned long ul = 0x12345678;

    // 호스트 바이트를 네트워크 바이트로 변환한다.
    printf("0x%08X = > 0x%08X\n", us, htons(us));
    printf("0x%08X = > 0x%08X\n", ul, htonl(ul));

    unsigned short n_us = htons(us);
    unsigned long n_ul = htonl(ul);
    // 네트워크 바이트를 호스트 바이트로 변환한다.
    printf("0x%08X = > 0x%08X\n", n_us, ntohs(n_us));
    printf("0x%08X = > 0x%08X\n", n_ul, ntohl(n_ul));

    WSACleanup();
    return 0;
}

 

소켓 구조체

소켓을 사용하기 위해 필수적으로 사용되는 구조체는 sockaddr 구조체와 sockaddr_in 구조체가 있습니다.

 

sockaddr 구조체의 정의는

typedef struct sockaddr {

u_short sa_family; // Address family.
    CHAR sa_data[14];  // Up to 14 bytes of direct address.
} SOCKADDR, *PSOCKADDR, FAR *LPSOCKADDR;
  • sa_family는 2바이트 크기로 주소 체계를 지정합니다. TCP , UDP 프로토콜은 AF_INET(PF_INET)을 사용하게 됩니다.
  • sa_data[14]는 6바이트에 IP주소와 포트 번호가 지정되며 나머지 8바이트는 예약되어 사용되지 않습니다.
  • 위 구조체는 프로그램에서 IP 주소와 포트 번호를 지정하기 위해 비트연산을 수행해야 하므로 좀 더 사용하기 편한 sockaddr_int 구조체를 사용할 수 있습니다.

 

typedef struct sockaddr_in {

short   sin_family;    
    USHORT sin_port;
    IN_ADDR sin_addr;
    CHAR sin_zero[8];
} SOCKADDR_IN, *PSOCKADDR_IN;

 

  • sin_family에는 2바이트 주소 체계를 지정합니다.
  • sin_port에는 2바이트 정수 포트 번호를 지정합니다.
  • sin-addr에는 4바이트 정수 IP 주소를 지정합니다.
  • sin_zero[8]는 예약되어 사용되지 않습니다.

IN_ADDR 구조체의 정의로 IP주소를 1,2,4 바이트 단위로 쉽게 접근할 수 있도록 제공하는 구조체입니다.

typedef struct in_addr {
        union {
                struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
                struct { USHORT s_w1,s_w2; } S_un_w;
                ULONG S_addr;
        } S_un;
#define s_addr  S_un.S_addr /* can be used for most tcp & ip code */
#define s_host  S_un.S_un_b.s_b2    // host on imp
#define s_net   S_un.S_un_b.s_b1    // network
#define s_imp   S_un.S_un_w.s_w2    // imp
#define s_impno S_un.S_un_b.s_b4    // imp #
#define s_lh    S_un.S_un_b.s_b3    // logical host
} IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;

sockaddr 구조체와 sockaddr_in 구조체를 비교

 

728x90
반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기