'endian'에 해당되는 글 2건

  1. 2009.12.15 bind()
  2. 2009.10.06 Little Endian 과 Big Endian
2009. 12. 15. 10:30

bind()



통신을 위한 소켓을 생성하고나면, 소켓에 주소를 할당해야 한다. 이때 사용하는 함수가 'bind()' 이다.

#include <sys/types.h>
#include <sys/socket.h>

int bind(int sockfd, struct sockaddr *myaddr, int addrlen);

  • sockfd - 주소를 할당하고자 하는 소켓의 파일 디스크립터
  • myaddr - 할당하고자 하는 주소정보를 가지고 있는 구조체 변수의 포인터
  • addrlen - 인자로 전달되는 주소정보 구조체의 길이
  • 리턴값 - 성공 시 0, 실패 시 -1 을 리턴

두 번째 인자 myaddr는 struct sockaddr* 형이지만, 실제는 sockaddr_in을 형변환 한 것이다.
sockaddr_in을 살펴보면...

struct sockaddr_in {
    sa_family_t     sin_family;        // 소켓 타입
    uint16_t           sin_port;          // 연결에 사용되는 포트 번호
    struct in_addr  sin_addr;         // 연결을 받아들일 주소
    char               sin_zero[8];    // 사용되지 않음
}

struct in_addr {
    uint32_t    s_addr;                  // IPv4 인터넷 주소
}


소켓 생성을 해서 소켓에 주소를 할당하는 bind() 까지의 예

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

serv_sock = socket(PF_INET, SOCK_STREAM, 0);        /* 소켓 생성 */
if(serv_sock == -1)
// error 처리..
 
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;                               // 소켓 타입
serv_addr.sin_addr.s_addr = inet_addr(serv_ip);         // IP 주소
serv_addr.sin_port = htons(atoi(serv_port));               // 포트 번호 

if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1)     /* 소켓에 주소 할당 */
// error 처리..
...


추가 #1.
소켓에 사용되는 모든 데이터는 Big Endian으로 동작한다. 일반적으로 사용하는 기계가 Little Endian 인경우가 대부분이고, 혹시나 모르기 때문에 소켓에 사용되는 데이터(IP 주소, 포트 번호 등)은 네트워크 바이트 순서(Big Endian)으로 변경해 주어야 한다.
이 때 사용되는 함수가 htons(), ntohs(), htonl(), ntohl() 이다.
h - host byte
n - network byte
l - long (32bit)
s - short (16bir)
htons()라고 한다면 short형의 host byte를 short형의 network byte로 변경해준다는 의미이다.
[참고] Endian에 대해서는 이곳을 참고!!!

추가 #2.
IP 주소를 보면 127.0.0.1 과 같은 형태인 것을 볼 수 있다. 하지만 실제 사용될 때에는 unsigned long 형으로 표현이 된다.
127.0.0.1 과 같은 형태를 'Dotted-Decimal Notation'이라고 부르며, 이는 위의 예제 소스에서 확인 할 수 있듯 문자열이다. 이를 unsigned long 형으로 바꾸어주는 함수가 'inet_addr()' 이다.

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

unsigned long inet_addr (const char* string);


추가 #3.
위의 예제 소스를 보면 IP 주소를 직접 입력했다. 하지만 직접 IP 주소를 입력할 경우 다른 기계에서 동작을 할 수 없게 된다. 각 기계마다 IP 주소가 동일한 것이 아니기에...
이 때 'INADDR_ANY' 라는 상수를 통해서 현재 시스템의 IP를 자동으로 찾아서 할당해 주는 방법을 사용할 수 있다.

...   
char *serv_port = "9190";
struct sockaddr_in serv_addr;
...
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;                                         // 소켓 타입
serv_addr.sin_addr.s_addr = inet_addr(INADDR_ANY);         // IP 주소
serv_addr.sin_port = htons(atoi(serv_port));                          // 포트 번호 
...


 

'Programmings > TCP/IP socket programming' 카테고리의 다른 글

connect()  (0) 2009.12.18
listen() and accept()  (0) 2009.12.16
socket()  (0) 2009.12.15
2009. 10. 6. 17:36

Little Endian 과 Big Endian



엔디안(Endian)이라는 단어 솔직히 컴퓨터 관련 업종에 있다보면 수없이 들어봤음직한 단어이다.
그런데도 갑자기 Endian 이 뭐냐고 물어보면... 뭐라고 해야하나?? -_-;;

간단히 말하면..
Endian이란 녀석.. 메모리란 1차원적인 공간의 데이터를 처리하기 위한 접근 방식이라고 하면 될려나??

일단 컴퓨터를 통해 무엇인가를 하려 한다면 메인 메모리에 접근을 해야만한다. 그런데 이 메인 메모리에 접근하는 데에도 방식이 있단다.
바로 Endian!!
이것이 헷갈리는 이유는 Endian이 하나가 아니고 두개라서(?) ㅋ

먼저 Big Endian 이란 녀석을 보자.
구글에서 검색을 하니 이런 사진이 검색이 되던데.. 설명하기에 좋은 사진인 듯 하다.
한 워드의 데이터가 메인 메모리 공간에 접근할 때, 데이터의 가장 상위 바이트가 메모리의 가장 낮은 주소로 접근하는 방식이다. 물론 데이터의 가장 하위 바이트는 메모리의 가장 큰 주소로 접근할 것이다.
이것이 Big Endian 이란 녀석이다.

Big Endian은 표현되는 순서가 사람이 보는 관점과 동일하다. 그렇기 때문에 디버깅이라든지 다른 작업시 메모리 값을 확인하기가 편하다.
예를 들어 0x12345678 이라는 값이 있다면, 각 메모리 주소에는 0x12, 0x34, 0x56, 0x78 이 들어있게 되는 것이다.

다음은 Little Endian..
Little Endian 은 Big Endian 과 정 반대의 접근 방식이라고 보면 된다.
한 워드의 데이터가 메인 메모리 공간에 접근을 한다면, 데이터의 가장 상위 바이트는 메모리의 가장 상위의 주소로 접근을 하고, 데이터의 가장 하위 바이트는 메모리의 가장 낮은 주소로 접근을 하게 된다.
위에서 예를 든 0x12345678을 Little Endian 식으로 표현을 하면 메모리 주소에는  0x79, 0x56, 0x34, 0x12 가 들어있게 된다.

Little Endian 이든 Big Engian 이든 한 바이트 단위로 접근을 한다면 아무런 문제 없이 사용할 수 있다. 하지만, 그 이상의 단위로 접근을 하게 될 때에 이를 잘못 사용한다면.. 뭐 정상적인 동작을 하지 않을 것이다.
컴퓨터란 녀석한테는 무지 중요한 개념(?) 중 하나인 것이다. 개념 컴퓨터... ㅋㅋ

뭐 당연한 이야기인가?? -_-;;