본문 바로가기
Computer Science/TCP&IP 소켓 프로그래밍

3-3. IP 주소 변환 함수 ( inet_addr, inet_ntoa, WASAddressToString, WSAStringToAddress)

by JI NY 2023. 11. 25.

3-3. IP 주소 변환 함수

( inet_addr, inet_ntoa, WASAddressToString, WSAStringToAddress)


01. IP 주소 변환 함수

1) IP 주소 변환 예시

  • 윈도우 응용 프로그램에서 IP 주소를 입력받을때, ‘문자열’ 형태로 전달받게 되므로 네트워크 통신을 위해 이를 32bit( IPv4)나 128bit(IPv6) 숫자로 변환해야한다.
  •  

 


02. IPv4 주소 변환 함수

응용 프로그램에서 IP 주소를 편리하게 변환할 수 있도록 다음과 같은 윈속 함수가 제공된다.

1) inet_addr() : 문자열 → 숫자

"Internet Address”

→ 문자열 형태로 (IPv4 주소 입력**(”170.0.0.1”)** → 32bit 숫자(네트워크 바이트 정렬)로 리턴

// IPv4 주소 변환
// 문자열 -> 숫자
unsigned long inet_addr (const char *cp);

 

 

2) *inet_ntoa() : 숫자 → 문자열

Internet to ASCII

→ 32bit 숫자 (네트워크 바이트 정렬)로 IPv4 주소 입력 → 문자열 형태로 리턴

// 숫자 -> 문자열
char *inet_ntoa (struct in_addr in);

  • 참고 : IN_ADDR 구조체

 

3) 예시

  • 바이트 정렬 함수와 IP 주소 변환 함수를 SOCKADDR_IN 구조체에 사용하는 예이다.
  1. 소켓 주소 구조체 초기화 및 소켓 함수에 넘겨준다.(SocketFunc()은 임의의 소켓 함수)
    // 소켓 구조체 초기화
    SOCKADDR_IN addr;
    ZeroMemory(&addr, sizeof(addr));	// 0으로 채움
    addr.sin_family = AF_INET; //IPv4
    addr.sin_addr.s_addr = inet_addr("123.456.789.0");	// 문자열을 32비트 IPv4 주소로 변환하여 넣음
    addr.sin_port = htons(9000);	// 네크워크 바이트 정렬을 하여 넣음
    
    // 소켓 함수 호출
    SocketFunc(..., (SOCKADDR *) &addr, sizeof(addr), ...);
    
  2. 소켓 함수가 소켓 주소 구조체를 입력으로 받아 내용을 채우면, 응용 프로그램이 이를 출력 등의 목적으로 사용(SocketFunc()은 임의의 소켓 함수)
// 소켓 함수 호출
SOCKADDR_IN addr;
int addrlen = sizeof(addr);
SocketFunc(..., (SOCKADDR *) &addr, &addrlen, ...);

// 소켓 주소 구조체 사용
printf("IP 주소=%s, 포트 번호=%d\\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
// ip 주소를 문자열로 바꾸고 정수 형태로 받았음. networkTohost

 

 

3) IP 주소 변환 함수 주의점

1. inet_addr() 함수는 이미 네트워크 바이트 정렬된 IP 주소를 리턴하기 때문에 htonl() 함수를 다음과 같이 적용하면 안된다.

addr.sin_addr.s_addr = htonl(inet_addr("123.456.789.0"));	→ (X)

 

 

2. inet_ntoa은 이미 네트워크 바이트 정렬된 IP 주소이기 때문에 ntohl() 함수를 다음과 같이 적용하면 안된다

printf("IP 주소=%s, 포트 번호=%d\\n", inet_ntoa(ntohl(addr.sin_addr(), ntohs(addr.sin_port)); → (X)

 


 

03. IPv4 와 IPv6 주소 변환 확장 함수

  • IPv4, IPv6 모두 주소 변환이 가능하게 한 것.

1) WSAStringToAddress() 문자열 → 숫자

int WSAStringToAddress (
   // 문자열 형식의 IP 주소
   LPTSTR AddressString, // [in]
   // AF_INET 또는 AF_INET6
   INT AddressFamily,
   // NULL
   LPWSAPROTOCOL_INFO lpProtocolInfo,
   // IP 주소(숫자)를 저장할 구조체; SOCKADDR_IN 또는 SOCKADDR_IN6
   LPSOCKADDR lpAddress, //[out]
   // 주소 구조체의 길이
   LPINT lpAddressLength
);

2) WSAAddressToString() : 숫자 → 문자열

int WSAAddressToString (
   // 숫자 형식의 IP 주소; SOCKADDR_IN 또는 SOCKADDR_IN6
   LPSOCKADDR lpsaAddress, //[in]
   // 주소 구조체의 길이
   DWORD dwAddressLength,
   // NULL
   LPWSAPROTOCOL_INFO lpProtocolInfo,
   // IP 주소(문자열)를 저장할 버퍼
   LPTSTR lpszAddressString, //[out] 문자열로 변환된걸 받을곳
   // 버퍼의 길이
   LPDWORD lpdwAddressStringLength
);

 

 

3) 바이트 정렬 함수 연습

#pragma comment(lib, "ws2_32")
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
	WSADATA wsa;
	if(WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
		return 1;

	/*----------------*/
	/* IPv4 변환 연습 */
	/*----------------*/
	// 원래의 IPv4 주소 출력
	char *ipv4test = "147.46.114.70"; //문자열로 받았음.
	printf("IPv4 주소(변환 전) = %s\\n", ipv4test);

	// inet_addr() 함수 연습
	printf("IPv4 주소(변환 후) = 0x%x\\n", inet_addr(ipv4test)); //문자 주소를 -> 숫자로 바꾸고 네트워크 바이트 정렬도 시켰음.

	// inet_ntoa() 함수 연습
	IN_ADDR ipv4num;
	ipv4num.s_addr = inet_addr(ipv4test); //구조체의 s_addr에 대입
	printf("IPv4 주소(다시 변환 후) = %s\\n", inet_ntoa(ipv4num)); //받았을때, 다시 숫자주소를 -> 문자 주소로 바꿈.

	printf("\\n");

	/*----------------*/
	/* IPv6 변환 연습 */
	/*----------------*/
	// 원래의 IPv6 주소 출력
	char *ipv6test = "2001:0230:abcd:ffab:0023:eb00:ffff:1111";
	printf("IPv6 주소(변환 전) = %s\\n", ipv6test);

	// WSAStringToAddress() 함수 연습
	SOCKADDR_IN6 ipv6num;
	int addrlen = sizeof(ipv6num);
	WSAStringToAddress(ipv6test, AF_INET6, NULL,
		(SOCKADDR *)&ipv6num, &addrlen);
	printf("IPv6 주소(변환 후) = 0x");
	for(int i=0; i<16; i++)
		printf("%02x", ipv6num.sin6_addr.u.Byte[i]);
	printf("\\n");

	// WSAAddressToString() 함수 연습
	char ipaddr[50];
	DWORD ipaddrlen = sizeof(ipaddr);
	WSAAddressToString((SOCKADDR *)&ipv6num, sizeof(ipv6num),
		NULL, ipaddr, &ipaddrlen);
	printf("IPv6 주소(다시 변환 후) = %s\\n", ipaddr);

	WSACleanup();
	return 0;
}

 

 


  • 참고자료
    • - TCP/IP 윈도우 소켓 프로그래밍 [한빛아카데미]

댓글