소켓프로그래밍 - 구조체 보내기...

kernelbomb의 이미지

안녕하세요?

UNP를 보고 공부하고 있는데요.

숫자의 경우 UNP에선 문자로 만들어 보내던지 빅엔디언으로 넷똑에

보내고 받을 때는 호스트에 바이트오더에 맞게 받으면 된다고 하는데요.

아래 소스를 실행시키면 이상하게 동작합니다.

서버측 보내는 프로그램

 void str_echo(int sockfd)
      {
          ssize_t n;
          struct  args    args;
          struct  result  result;
      
          for (;;)
          {
              if ((n = readline(sockfd, &args, sizeof(args))) == 0)
                  return;
      
              printf("SERVER : arg1 = %ld\t arg2 = %ld\n", ntohl(args.arg1), ntohl(args.arg2));
              result.sum = htonl(args.arg1 + args.arg2);
              writen(sockfd, &result, sizeof(result));
         }
     }

클라이언트의 보내는 프로그램

 void str_cli(FILE *fp, int sockfd)
{
          char    sendline[MAXLINE], recvline[MAXLINE];
          struct  args    args;
          struct  result  result;
      
          while(fgets(sendline, MAXLINE, fp) != NULL)
          {
              if (sscanf(sendline, "%ld%ld", &args.arg1, &args.arg2) != 2)
              {
                  printf("invalid input : %s", sendline);
                  continue;
              }
      
              printf("CLIENT : arg1 = %ld\t arg2 = %ld\n", args.arg1, args.arg2);
              args.arg1 = htonl(args.arg1);
              args.arg2 = htonl(args.arg2);
              writen(sockfd, &args, sizeof(args));
      
              if (readn(sockfd, &result, sizeof(result)) == 0)
                  printf("str_cli : server terminated prematurely\n");
      
              printf("CLIENT : %ld\n", ntohl(result.sum));
          }
      }

구조체는 아래와 같습니다.

struct  args {
        unsigned long    arg1;
        unsigned long    arg2;
};

struct  result {
        unsigned long    sum;
};

실행하면 아래와 같이 나옵니다.

Quote:
[root@tacstar Stevens]# ./tcpcli02 192.168.1.46
11 22 <--- 입력
CLIENT : arg1 = 11 arg2 = 22
SERVER : arg1 = 11 arg2 = 0 <--- 왜 0이 나올까요?
CLIENT : CLIENT : 184549376 <--- 이건 또 왜그렇죠? ntohl();을 썼는데...
amister의 이미지

1. SERVER 측에서 ntohl(args.arg2) 가 0으로 찍히는 것은 분명 이상하군요. 코드 상으로는 문제 없어보입니다. 서버와 클라이언트의 struct args 구조가 틀리거나 readline(), writen() 등의 구현이 잘못되어있지 않나 추측됩니다.

2. SERVER 측에서 result.sum을 계산하는 코드에 오류가 있습니다. 다음과 같이 수정되어야 합니다.

result.sum = htonl(ntohl(args.arg1) + ntonl(args.arg2));

김충길의 이미지

n = readline (...) 의 n을 출력 해보세요.

writen(...) 라인의 쓴 바이트도 출력 해보시고요.

readline에서 받은 값들을 hex 로 바이트 단위로 찍어보시고
writen 함수내에서도 바이트 단위로 찍어 보세요.

screen + vim + ctags 좋아요~

kernelbomb의 이미지

감사합니다. *^^*

문제는 readline(); 함수더군요.

그런데 더 웃낀 문제가 있습니다.

클라이언트 코드

void str_cli(FILE *fp, int sockfd)
{
        ssize_t n;
        char    sendline[MAXLINE], recvline[MAXLINE];
        struct  args    args;
        struct  result  result;

        while(fgets(sendline, MAXLINE, fp) != NULL)
        {
                if (sscanf(sendline, "%ld%ld", &args.arg1, &args.arg2) != 2)
                {
                        printf("invalid input : %s", sendline);
                        continue;
                }

                printf("CLIENT : arg1 = %ld\t arg2 = %ld\n", args.arg1, args.arg2);
                printf("CLIENT : arg1 = 0x0%x\t arg2 = 0x0%x\n", htonl(args.arg1), htonl(args.arg2));

                args.arg1 = htonl(args.arg1);
                args.arg2 = htonl(args.arg2);

                n = writen(sockfd, &args, sizeof(args));
                printf("CLIENT : n = %d\n", n);

                if ((n = readn(sockfd, &result, sizeof(result))) == 0)
                        printf("str_cli : server terminated prematurely\n");

                printf("CLIENT : n = %d\n", n);
                printf("CLIENT : %ld\n", ntohl(result.sum));
        }
}

서버코드

void str_echo(int sockfd)
{
        ssize_t n;
        struct  args    args;
        struct  result  result;

        for (;;)
        {
                if ((n = readn(sockfd, &args, sizeof(args))) == 0)
                        return;

                printf("SERVER : n = %d\n", n);
                printf("SERVER : arg1 = %ld\t arg2 = %ld\n", ntohl(args.arg1), ntohl(args.arg2));

                result.sum = htonl(args.arg1) + htonl(args.arg2);
                n = writen(sockfd, &result, sizeof(result));
                printf("SERVER : n = %d\n", n);
        }
}

실행화면

Quote:
[root@tacstar Stevens]# ./tcpcli02 192.168.1.46
10 11 <--- 입력값
CLIENT : arg1 = 10 arg2 = 11
CLIENT : arg1 = 0x0a000000 arg2 = 0x0b000000 <--- 빅엔디언 변환값
CLIENT : n = 8 <--- 구조체(args) 바이트 8byte
SERVER : n = 8
SERVER : arg1 = 10 arg2 = 11
SERVER : n = 4 <--- 구조체(result) 바이트 4byte
CLIENT : n = 4
CLIENT : 352321536 <--- ntohl();을 썼는데 이상한 값 출력

마지막 클라리언트의 출력(두수의 합)하는 것을 보면 이상하게 나오네요.

분명 클라이언측에서 출력 시, ntohl(); 함수를 사용했는데...

ntohl();을 빼고 하면 정상적인 값이 나옵니다.

당신들을 사랑합니다.

김충길의 이미지

result.sum = htonl(args.arg1) + htonl(args.arg2);

이코드가 이상한데요. 왜 network byte ordering 한걸 더하나요?

어떨땐 코드 째려보기 신공이 디버깅이 빠를때가 있으니 이용해 보세요.

screen + vim + ctags 좋아요~

불량청년의 이미지

서버측 코드를 보시면 printf문에서 args구조체 값을 출력하는데

ntohl(); 함수를 사용하셨네요. *^^*

printf(); 함수의 인자로 넘겨준 값은 변하는게 아니겠죠.

즉, 코드상에선 args 구조체 값은 여전히 network byte order로

되어 있군요. 그 값에 다시 htonl(); 함수를 사용하니 이상하게

나오는거 아닌가요?

많이 헷갈리는 부분인거 같네요. 그래서 값을 읽은 후에는 바로 그 값을

host byte order 로 바꿔준 후에 사용하는게 좋을꺼 같네요. 그럼...

H/W가 컴퓨터의 심장이라면 S/W는 컴퓨터의 영혼이다!

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.