htonl , ntohl에 대한 질문입니다.

anaud2의 이미지

안녕하세요
열심히 프로젝트를 하는 사람입니다.
오늘 인디언 문제로 갑자기 골머리를 앓아서 질문을 드립니다.

책에서는 (윤성우저(TCP&IP소켓 프로그래밍)htonl과 ntohl에 대해

htonl host byte to network byte순으로 바꿔준다
ntohl network byte to host byte 순으로 바꿔준다

라고 나와있습니다.

프로젝트를 하면서 #ifdef 를 사용해서 빅인디언일때와 리틀인디언일때를 각각 나눠서 변형을 시켰습니다.
(통신은 빅으로 맞춰준다란 부분이 있다곤 알고 있지만 서버에 맞추란 상관의 지시에따라..)

ex)

a = 2;
#ifdef BIG
a = htonl(a);
#endif
#ifdef LITTLE
a = ntohl(a);
#endif

그런데 실험중에 클라이언트가 리틀이고 서버가 빅일때 -DBIG을 주던지 -DLITTLE을 주던지 통신이 됩니다.
ntohl이나 htonl이나 모두다 자신의 인디언체계를 반대되는 인디언 체계로 바꿔주는 동작을 하더군요..

결국 서버랑 인디언체계가 반대된다면 두개 함수중 아무거나 사용해도 된다.. 호스트바이트를 네트워크 바이트로 바꾸는게 아니라 그냥 바꾸는게 되는거 같습니다.

함수를 다르게 놓은건 구분인거 같구요..

a = 2;
#ifdef ENDIANCH
a = htonl(a);
#endif

현재는 이런형태로 바꿨습니다. 인디언이 다를경우 컴파일때 -DENDIANCH를 하라..
제가 보기엔 두함수가 동작이 똑같고 인디언이 다를때만 아무가나 호출해도 될꺼같습니다.
제가 틀리거나 모르는 사항이 있으면 지도 부탁드립니다..
잘못하면 프로젝트가 큰일나서..
아래는 실험 내용과 결과 입니다.

======================
실험
======================
int main(void)
{
int i, big,litte,big2, litte2;
i = 0x12345678;
big = htonl(i);
litthe = ntohl(i);

big2 = ntohl(big);
litthe2 = htonl(litthe);

printf("big[%x]\n",big);
printf("little[%x]\n",litthe);
printf("big[%x]\n",big2);
printf("little[%x]\n",litthe2);
}

big[78563412]
little[78563412]
big[12345678]
little[12345678]
==========================================

mithrandir의 이미지

Big endian host에서는 위 함수는 아무런 동작을 하지 않습니다.

Little endian host에서 두 함수는 똑같이 endian을 뒤집는 같은 동작을 합니다.
다만 해당 인자나 반환값이 어떤 의미를 지니는지에 따라 함수를 다르게 사용하는 것이 코드 가독성을 높일 수 있습니다.

따라서 컨벤션을 따른다면, 서버가 little endian이라고 해서 네트워크 패킷을 little endian으로 보낸다면 상당히 불편할 수 있지요. (위에 서버에 맞춘다는 얘기가 어떤 얘기인지는 모르겠습니다마는)

언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net

언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net

anaud2의 이미지

서버에 맞춘다는 말은 님이 지적하신대로 서버가 little endian 일때 little endian으로 패킷을 보낸다는 의미입니다.

빅인디언 시스템에서 해보니까 전혀 반응이 없네요 그렇다면 서버 시스템에 맞춰서 인디언 시스템을 바꿔줄수 없다는 말인거 같네요

만약 그런데도 바꿔라고 한다면 정말 나쁜 상사인거네요-_-;;

pizza1977의 이미지

귀찮지만...하라면 해야죠...
대부분은 정책을 정하죠. 통신은 무조건 리틀 또는 빅. 그것에 맞추어 알아서 변환.
이런식인데...어짜피 바이트 단위의 연산은 의미가 없고, 2byte, 4byte에 맞는
함수 하나 만드세요.

-------------
포탈이는 불사신

-------------
포탈이는 불사신

anaud2의 이미지

쉽사리 생각은 안떠오르네요 어떻게 서로 위치를바꿔줘야 할지

빅과 리틀이 어떤순서로 되는지는 알고 있지만 바이트 단위에 수가 들어있는걸 카피해서 위치를 옮긴다..

쉽사리 아이디어는 안떠오르네요..하라고 한다면 업무가 안그래도 밀려있는데...몇일밤은 새야겠네요

hayarobi의 이미지

//#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
 
uint32_t swapl(uint32_t longval) {
    uint32_t result = 0;
    char *dest = (char*)(&result)+3;
    char * src = (char*)(&longval);
    int i;
    for(i=0;i<4;i++) {
        *(dest--) = *(src++);
    }
    return result;
}
 
uint16_t swaps(uint16_t shortval) {
    uint16_t result = 0;
    char *dest = (char*)(&result);
    char * src = (char*)(&shortval);
    *dest = *(src+1);
    *(dest+1) = *(src);
    return result;
}
 
void main() {
    uint16_t shortval = 0x1234;
    uint32_t longval = 0x12345678;
    printf("%04X to %04X \n",shortval,swaps(shortval) );
    printf("%08X to %08X \n",longval,swapl(longval) ); 
}

함수의 인자타입은 POSIX기준을 따랐습니다. uint16_t 같은 것은 linux에서는 stdint.h에서 가져와서 썼는데 썬 장비에서는 해당 헤더 파일이 없었던 것으로 기억합니다. inttypes.h가 대충 공통 헤더로 사용이 가능한 것 같더군요. 기본으로 제공하는 함수가 4비트까지만 있어서 8비트 숫자를 변환하기 위해 만든 적이 있던 것을 조금 수정해 봤습니다.

댓글 적으면서 생각났는데 swap함수로 매번 ifdef처리하는 것 보다는 그냥 to_server_endian같은 이름의 함수를 포인터 형식으로 만들어서 적절하게 엔디안 지정하는 것도 한 방법일 듯 합니다.

=================
잠못자는 한솔아빠

=================
잠못자는 한솔아빠

anaud2의 이미지

일단 다른 업무를 우선봐야해서 직접 실행은 못해봤지만
답변 너무 감사드립니다.
차후에 실행시 질문사항이 생기면 다시 문의를 좀 드리겠습니다.
즐거운 하루되세요^^

cococo의 이미지

제가 제대로 이해했는지 모르겠는데요.
예를들어 ntohl() 일경우... 이 함수 자체가 network > BIG / host > LITTLE 로 가정하고 바꾸는 거 아닌가요? 즉, 함수 자체에 네트웤 / 호스트가 BIG/LITTLE중 어떤 걸 쓰고 있는지는 판단하지 않는다...
이렇게 알고 있는데요. 틀린 건가요?
(실제로 다른 환경에서 실험해 본 적은 없..-_-;;)

행복은 희생없이는 얻을 수 없는 것인가?
시대는 불행없이는 넘을 수 없는 것인가?

purluno의 이미지

호스트의 byte order에 따라 판단합니다.

glibc의 netinet/in.h를 보면

이런 코드가 있죠.

#ifdef __OPTIMIZE__
/* We can optimize calls to the conversion functions.  Either nothing has
   to be done or we are using directly the byte-swapping functions which
   often can be inlined.  */
# if __BYTE_ORDER == __BIG_ENDIAN
/* The host byte order is the same as network byte order,
   so these functions are all just identity.  */
# define ntohl(x)       (x)
# define ntohs(x)       (x)
# define htonl(x)       (x)
# define htons(x)       (x)
# else
#  if __BYTE_ORDER == __LITTLE_ENDIAN
#   define ntohl(x)     __bswap_32 (x)
#   define ntohs(x)     __bswap_16 (x)
#   define htonl(x)     __bswap_32 (x)
#   define htons(x)     __bswap_16 (x)
#  endif
# endif
#endif

cococo의 이미지

몰랐네요.
답변 감사합니다.

행복은 희생없이는 얻을 수 없는 것인가?
시대는 불행없이는 넘을 수 없는 것인가?

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.