관리 메뉴

Value Creator의 IT(프로그래밍 / 전자제품)

Chapter 3 소켓 주소 체계와 데이터 정렬 본문

1. 프로그래밍/4) Network

Chapter 3 소켓 주소 체계와 데이터 정렬

valuecreatort 2019. 10. 29. 20:14
반응형
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
	struct sockaddr_in addr1, addr2;
	char *str_ptr;
	char str_arr[20];
   
	addr1.sin_addr.s_addr=htonl(0x1020304);
	addr2.sin_addr.s_addr=htonl(0x1010101);
	
	str_ptr=inet_ntoa(addr1.sin_addr);
	strcpy(str_arr, str_ptr);
	printf("Dotted-Decimal notation1: %s \n", str_ptr);
	
	inet_ntoa(addr2.sin_addr);
	printf("Dotted-Decimal notation2: %s \n", str_ptr);
	printf("Dotted-Decimal notation3: %s \n", str_arr);
	return 0;
}

/*
root@com:/home/swyoon/tcpip# gcc inet_ntoa.c -o ntoa
root@com:/home/swyoon/tcpip# ./ntoa
Dotted-Decimal notation1: 1.2.3.4 
Dotted-Decimal notation2: 1.1.1.1 
Dotted-Decimal notation3: 1.2.3.4 

*/

1. 이 구조체에 IP주소와 PORT 번호가 담겨있다.

struct sockaddr_in

{

  sa_family_t   sin_family; //주소체계

  uint16_t   sin_port; // Port 번호. 16비트.

  struct in_addr  sin_addr; //32비트 IP주소

  char  sin_zero[8] ; // 미사용. 반드시 0으로 채운다.

};

 

struct in_addr

{

  in_addr_t  s_addr; //32비트 IPv4 인터넷 주소

}

 

 

socklen_t : 길이 정보

in_port_t : port번호 정보

 

sin_family는 3종류가 있다.

AF_INET : IPv4

AF_INET6 : IPv6

AF_LOCAL : 로컬통신

 

2. bind명령어

struct sockaddr_in serv_addr;

...

if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1)

  error_handling("bind() error");

구조체 변수 sockaddr_in은 bind 함수의 인자로 전달되는데, 매개변수 형이
sockaddr이므로 형 변환을 해야만 한다.

 

struct sockaddr

{

  sa_family_t  sin_family; //주소체계

  char  sa_data[14]; //주소정보

}

 

구조체 sockaddr은 다양한 주소체계의 주소정보를 담을 수 있도록 정의되었다. 그
래서 IPv4의 주소정보를 담기가 불편하다. 이에 동일한 바이트 열을 구성하는 구조
체 sockaddr_in이 정의되었으며, 이를 이용해서 쉽게 IPv4의 주소정보를 담을 수
있다.

 

3. 네트워크 통신은 '빅 엔디안' 기준이다.

 

상위 바이트 일수록 왼쪽에 저장된다.(작은 번지수)

 

왼쪽이 상위바이트, 오른쪽이 하위 바이트

왼쪽이 작은 번지수, 오른쪽이 큰 번지수

0x12345678

 

리틀엔디안은 위 값을

0x78 0x56 0x34 0x12로 저장한다.

 

4. 바이트 순서

h : host 바이트 순서

n : network 바이트 순서

s : 자료형 short

l : 자료형 Long

 

htons(호스트->네트워크, short)

ntohs(네트워크->호스트, short)

htonl(호스트->네트워크, Long)

ntohl(네트워크->호스트, Long)

 

호스트와 네트워크는 값을 뒤집어서 본다?

 

endian_conv.c

#include <stdio.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
	unsigned short host_port=0x1234;
	unsigned short net_port;
	unsigned long host_addr=0x12345678;
	unsigned long net_addr;
	
	net_port=htons(host_port);
	net_addr=htonl(host_addr);
	
	printf("Host ordered port: %#x \n", host_port);
	printf("Network ordered port: %#x \n", net_port);
	printf("Host ordered address: %#lx \n", host_addr);
	printf("Network ordered address: %#lx \n", net_addr);
	return 0;
}

결과

a@a:~/Desktop/NP/manual/TCPIP_Src/Chapter3$ gcc endian_conv.c -o conv
a@a:~/Desktop/NP/manual/TCPIP_Src/Chapter3$ ./conv
Host ordered port: 0x1234 
Network ordered port: 0x3412 
Host ordered address: 0x12345678 
Network ordered address: 0x78563412 

 

호스트가 0x1234로 보고 있으면 네트워크는 0x3412로 본다.

호스트가 0x12345678로 보고 있으면 네트워크는 0x78563412로 본다.

 

 

 

5. 문자열을 네트워크 바이트 순서의 정보로 변환

 

inet_addr.c

 

#include <stdio.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
	char *addr1="127.212.124.78";
	char *addr2="127.212.124.256";

	unsigned long conv_addr=inet_addr(addr1);
	if(conv_addr==INADDR_NONE)
		printf("Error occured! \n");
	else
		printf("Network ordered integer addr: %#lx \n", conv_addr);
	
	conv_addr=inet_addr(addr2);
	if(conv_addr==INADDR_NONE)
		printf("Error occureded \n");
	else
		printf("Network ordered integer addr: %#lx \n\n", conv_addr);
	return 0;
}

a@a:~/Desktop/NP/manual/TCPIP_Src/Chapter3$ gcc inet_addr.c -o addr
a@a:~/Desktop/NP/manual/TCPIP_Src/Chapter3$ ./addr
Network ordered integer addr: 0x4e7cd47f 
Error occureded 

 

addr1은 변환이 잘 되었고 addr2는 오류가 났다. 256이 들어가있어서 그런거 같다. 256을 255 이하의 숫자로 바꾸고 다시 컴파일 후 실행하면 변환이 잘 된다.

 

변환성공시 빅 엔디안으로 변환된 32비트 정수값 반환, 실패시 INADDR_NONE 반환.

 

 

 

inet_aton.c

 

#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
void error_handling(char *message);

int main(int argc, char *argv[])
{
	char *addr="127.232.124.79";
	struct sockaddr_in addr_inet;
	
	if(!inet_aton(addr, &addr_inet.sin_addr))
		error_handling("Conversion error");
	else
		printf("Network ordered integer addr: %#x \n", addr_inet.sin_addr.s_addr);
	return 0;
}

void error_handling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

 

inet_aton으로 변환 성공시 1, 실패시 0 반환.

 

 

 

 

 

 

inet_ntoa.c

 

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
	struct sockaddr_in addr1, addr2;
	char *str_ptr;
	char str_arr[20];
   
	addr1.sin_addr.s_addr=htonl(0x1020304);
	addr2.sin_addr.s_addr=htonl(0x1010101);
	
	str_ptr=inet_ntoa(addr1.sin_addr);
	strcpy(str_arr, str_ptr);
	printf("Dotted-Decimal notation1: %s \n", str_ptr);
	
	inet_ntoa(addr2.sin_addr);
	printf("Dotted-Decimal notation2: %s \n", str_ptr);
	printf("Dotted-Decimal notation3: %s \n", str_arr);
	return 0;
}

/*
root@com:/home/swyoon/tcpip# gcc inet_ntoa.c -o ntoa
root@com:/home/swyoon/tcpip# ./ntoa
Dotted-Decimal notation1: 1.2.3.4 
Dotted-Decimal notation2: 1.1.1.1 
Dotted-Decimal notation3: 1.2.3.4 

*/

 

네트워크 바이트 순서로 정렬된 정수를 눈으로 쉽게 볼수 있게 변환.

 

 

 

 

 

6. 소켓에 인터넷 주소 할당.

 

bind()는 성공시 0, 실패시 -1 반환.

 

#include <sys/socket.h>

int serv_sock;
struct sockaddr_in serv_addr;
char *serv_port="9190";

//서버 소켓 (리스닝 소켓) 생성
serv_sock = socket(PF_INET, SOCK_STREAM, 0);

//주소 정보 초기화
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(atoi(serv_port));

//주소 정보 할당
bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

 

 

 

 

반응형
Comments