처음부터 차근차근
바이트 순서 변환과 호스트 정보 송수신 관련 함수들 본문
endian
#include <stdio.h> // c 언어 파일 작성할 때 필요한 헤더
#include <unistd.h> // unix 계열 헤더
int main(void)
{
int nValue = 0x12345678; // int형 변수 선언
printf("Value : 0x%08X\n", nValue); // nValue값 출력
for (int i = 0; i < 4; i++) {
// 각 주소에 있는 값 출력
// 순서가 거꾸로 나온다! -> little-endian은 이런 식으로 거꾸로 정리가 되서 관리된다.
char* pC = (char*)&nValue + i;
printf("%p : 0x%02X\n", pC, *pC);
}
printf("\n");// 개행
return 0; // 프로그램 종료
}
실행결과
각 주소에 있는 값을 출력했을 때 순서가 거꾸로 출력되는 것을 볼 수 있다.
Little-endian은 이런 식으로 거꾸로 정리되어 관리된다.
Endian_htonl
#include <stdio.h> // c 언어 파일 작성할 때 필요한 헤더
#include <unistd.h> // unix 계열 헤더
#include <arpa/inet.h>
int main(void)
{
// 변수 선언
int nValue = 0x12345678;
uint32_t nNetValue = 0;
printf("nValue : 0x%08X\n", nValue); // nValue값 출력
nNetValue = htonl(nValue); // 네트워크 형태의 값으로 변경
printf("nNetValue : ox%08X\n", nNetValue); // nNetValue 값 출력
for (int i = 0; i < 4; i++) {
// 각 주소에 있는 nNetValue 값 출력
char* pC = (char*)&nNetValue + i;
printf("%p : 0x%02X\n", pC, *pC);
}
return 0; // 프로그램 종료
}
실행결과
변형이 된 값인 nNetValue는 순서가 바이트단위로 뒤바뀌어 출력된 것을 볼 수 있고,
각 주소에 있는 값을 보면 nNetValue의 순서대로(12, 34…) 출력되는 것을 볼 수 있다.
Inet_addr
#include <stdio.h> // c 언어 파일 작성할 때 필요한 헤더
#include <unistd.h> // unix 계열 헤더
#include <arpa/inet.h> // inet_addr() 함수 사용할 때 필요
// argc : 명령 파라미터의 개수(자기 자신까지 1개로 침)
// argv[] : 각각의 아규멘트의 값들(argv[0]는 자기자신)
int main(int argc, char* argv[])
{
// 변수 선언
in_addr_t stAddr; // 정수형
unsigned char* p = (unsigned char*)&stAddr;
if (argc != 2) return -1;
// 매개변수(ip주소) 출력
printf("IP Adress is %s\n", argv[1]);
stAddr = inet_addr(argv[1]); // big-endien로 변환된 값
printf("IP Adress is 0x%X\n", stAddr); // big-endien로 변환된 값 출력
// 각 배열의 값 출력
printf("\t[0]=0x%02X\n", p[0]);
printf("\t[1]=0x%02X\n", p[1]);
printf("\t[2]=0x%02X\n", p[2]);
printf("\t[3]=0x%02X\n", p[3]);
return 0; // 프로그램 종료
}
실행결과
0x100000F : 정수형(in_addr_t형)으로 바뀐 것을 보면 순서가 반대로 된 것을 볼 수 있다.
(15를 16진수로 표현하면 0F임)
이렇게 거꾸로 나와있지만 배열 위치로 보면 순서가 제대로 잘 저장되어 있다.
Inet_network
#include <stdio.h> // c 언어 파일 작성할 때 필요한 헤더
#include <unistd.h> // unix 계열 헤더
#include <arpa/inet.h> // inet_network() 함수 사용할 때 필요
// argc : 명령 파라미터의 개수(자기 자신까지 1개로 침)
// argv[] : 각각의 아규멘트의 값들(argv[0]는 자기자신)
int main(int argc, char* argv[])
{
// 변수 선언
in_addr_t stAddr; // 정수형
unsigned char* p = (unsigned char*)&stAddr; // 포인터로 stAddr 주소 가리킴
// 명령 파라미터 개수가 2개가 아니면 프로그램 종료
if (argc != 2) return -1;
// 매개변수(ip주소) 출력
printf("IP Adress is %s\n", argv[1]);
stAddr = inet_network(argv[1]);
printf("Inet Adress is 0x%X\n", stAddr);// 매개변수로 넣은 값 출력
// 각 배열의 값 출력
printf("\t[0]=0x%02X\n", p[0]);
printf("\t[1]=0x%02X\n", p[1]);
printf("\t[2]=0x%02X\n", p[2]);
printf("\t[3]=0x%02X\n", p[3]);
return 0; // 프로그램 종료
}
실행결과
0xF000001 : 순서가 15.0.0.1과 동일하게 나오는 것을 볼 수 있다.
이렇게 동일하게 나오면 메모리 상에서는 거꾸로 기록된다.
그래서 배열의 값을 출력해봤을 때 거꾸로 출력되는 것을 볼 수 있다.
inet_aton
#include <stdio.h> // c 언어 파일 작성할 때 필요한 헤더
#include <unistd.h> // unix 계열 헤더
#include <arpa/inet.h> // inet_aton() 함수 사용할 때 필요
// argc : 명령 파라미터의 개수(자기 자신까지 1개로 침)
// argv[] : 각각의 아규멘트의 값들(argv[0]는 자기자신)
int main(int argc, char* argv[])
{
// 변수 선언
struct in_addr stAddr;
unsigned char* p = (unsigned char*)&stAddr; // 포인터로 stAddr 주소 가리킴
// 명령 파라미터 개수가 2개가 아니면 프로그램 종료
if (argc != 2) return -1;
// 매개변수(ip주소) 출력
printf("IP Adress is %s\n", argv[1]);
// bin-endien로 변환
if (inet_aton(argv[1], &stAddr) != 1) {// 1이 리턴되면 성공, 아니면 실패
perror("Failed to convert the address.");
return 0;
}
printf("Inet Adress is 0x%X\n", stAddr); // 매개변수로 넣은 값 변환해서 출력
// 각 배열의 값 출력
printf("\t[0]=0x%02X\n", p[0]);
printf("\t[1]=0x%02X\n", p[1]);
printf("\t[2]=0x%02X\n", p[2]);
printf("\t[3]=0x%02X\n", p[3]);
return 0; // 프로그램 종료
}
실행결과
0x100000F : 순서가 반대로 된 것을 볼 수 있다.
이렇게 거꾸로 나와있지만 배열 위치로 보면 순서가 제대로 잘 저장되어 있다.
Inet_ntoa
#include <stdio.h> // c 언어 파일 작성할 때 필요한 헤더
#include <unistd.h> // unix 계열 헤더
#include <arpa/inet.h> // inet_ntoa() 함수 사용할 때 필요
int main(void)
{
// 변수 선언
struct in_addr_t addr; // 정수형
char *ip_addr;
addr.s_addr = htonl(0x01020304); // 1234라는 값 대입
printf("Network Adress is 0x%X\n", addr); // addr 출력
// 네트워크 바이트 순서의 32비트 값을 dotted-decimal notation의 주소 값으로 변환
ip_addr = inet_ntoa(addr);
printf("IP Adress is %s\n", ip_addr); // ip_addr 출력
return 0; // 프로그램 종료
}
실행결과
Htonl에 의해 01020304가 거꾸로 출력되고,
inet_ntoa에 의해 형식이 변환되어 1.2.3.4로 출력되는 것을 볼 수 있다.
Inet_ntoa2
#include <stdio.h> // c 언어 파일 작성할 때 필요한 헤더
#include <unistd.h> // unix 계열 헤더
#include <arpa/inet.h> // inet_ntoa() 함수 사용할 때 필요
int main(void)
{
// 변수 선언
struct in_addr addr;
struct in_addr addr2;
char* ip_addr;
char* ip_addr2;
// big endian 방식으로 정렬 후 값 대입
addr.s_addr = htonl(0x01020304);
addr2.s_addr = htonl(0x12345678);
// 값 대입한거 출력
printf("Network Adress is 0x%X\n", addr);
printf("Network Adress2 is 0x%X\n", addr2);
// inet_ntoa 이용하여 dotted-decimal notation의 주소 값으로 변환
ip_addr = inet_ntoa(addr);
ip_addr2 = inet_ntoa(addr2);
// 값 대입한거 출력
printf("IP Adress is %s\n", ip_addr);
printf("IP Adress2 is %s\n", ip_addr2);
return 0; // 프로그램 종료
}
실행결과
0x4030201, 0x78563412 : htonl()으로 인해 값이 뒤집어져서 출력된다.
18.52.86.120 : Inet_ntoa()함수는 정적변수를 사용하기 때문에 adress와 adress2에 서로 다른 값을 넣어도 같은 값이 출력된다.
Gethostbyname()
<print_hostent.h>
#include <netdb.h>
void print_hostent(struct hostent* host);
<print_hostent.c>
#include <stdio.h> // c 언어 파일 작성할 때 필요한 헤더
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include "print_hostent.h"
void print_hostent(struct hostent* host)
{
int i;
printf("Official name of host : %s\n\n", host->h_name); // 파라미터로 받은 호스트 네임 출력
if (host->h_aliases[0] != NULL) // 별칭이 여러개 있으면
{
printf("--Aliases--\n");
// 별칭 출력
for (i = 0; host->h_aliases[i]; i++)
{
printf("%02dth: %s\n", i + 1, host->h_aliases[i]);
}
printf("\n");
}
// IPv4인지 IPv6인지 출력
printf("Adress type : %s\n\n",
(host->h_addrtype == AF_INET) ? "AR_INET" : "AF_INET6");
// ip 주소들 출력
printf("IP Adress : \n");
for (i = 0; host->h_addr_list[i]; i++)
{
// inet_ntoa를 이용해 dotted-decimal notation의 주소 값으로 변환하여 출력
printf("%02d : %s\n", i + 1,
inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
}
return;
}
<gethostbyname.c>
#include <unistd.h> // unix 계열 헤더
#include <stdio.h> // c 언어 파일 작성할 때 필요한 헤더
#include <netdb.h>
#include "print_hostent.h"
// argc : 명령 파라미터의 개수(자기 자신까지 1개로 침)
// argv[] : 각각의 아규멘트의 값들(argv[0]는 자기자신)
int main(int argc, char* argv[]) {
struct hostent* host;
// 파라미터 개수가 2개가 아니면
if (argc != 2) {
printf("usage : %s domain name\n", argv[0]);
return -1; // 종료
}
// 첫 번째 파라미터인 도메인 명을 4바이트의 네트워크 주소로 변환 후 대입
host = gethostbyname(argv[1]);
// gethostbyname()에서 null이 리턴되면
if (!host)
{
printf("gethostbyname function error\n");
return -1; // 종료
}
print_hostent(host); // 함수 호출
printf("Done.\n");
return 0; // 종료
}
실행결과
네이버를 파라미터로 넣었더니 네이버의 호스트 네임과 주소 타입, ip 주소가 출력되었다.
Gethostbyaddr
<gethostbyaddr.c>
#include <unistd.h> // unix 계열 헤더
#include <stdio.h> // c 언어 파일 작성할 때 필요한 헤더
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "print_hostent.h"
int main(int argc, char* argv[]) {
// 변수 선언
struct hostent* host;
uint32_t addr = 0;
// 파라미터 개수가 2개가 아니면
if (argc != 2)
{
printf("usage : %s domain name\n", argv[0]);
return -1; // 종료
}
addr = inet_addr(argv[1]); //IP 주소를 네트워크 바이트 정렬 방식의 4바이트 정수로 변환해서 대입
host = gethostbyaddr(&addr, 4, AF_INET); // 도메인명 얻음
// null이 반환되면
if (!host)
{
printf("gethostbyaddr function error\n");
return -1;
}
print_hostent(host); // 함수 호출
printf("Done.\n");
return 0; // 종료
}
실행결과
네이버의 아이피 주소를 파라미터로 넣었더니 address type과 host name 등이 출력되었다.
출처 : 네트워크개론(22-1학기)김병국교수 강의 내용 변형 및 요약
'Linux & Unix' 카테고리의 다른 글
tcp 소켓 생성과 TCP 클라이언트용 API (2) | 2022.05.22 |
---|---|
Unix 기본 시스템 함수 - getopt(), time(), localtime(), localtime_r(), ftime(), gettimeofday(), mktime(), 파일 기술자, bcopy() (0) | 2022.04.15 |
파일 접근과 해제, 읽기, 쓰기, 접근 위치 이동, 생성, 삭제 (0) | 2022.04.07 |
Virtual Box 공유 폴더 만들기, 명령어 정리 (0) | 2022.04.06 |
라이브러리와 아카이브, 에러 처리 (0) | 2022.03.01 |