Thread: trouble with hotns() ntohs()

  1. #1
    Lost in the C ZaC's Avatar
    Join Date
    Jun 2008
    Location
    Italy
    Posts
    47

    trouble with hotns() ntohs()

    I'm trying to understand how those * functions work...
    i have a server wich sends a uint16_t in network format and a client wich reads this uint16_t (this is for the example! my real program should work viceversa, the server reads a uint16_t in nwf from client and than sends the value of array[recivednum])

    this is the code of the server:
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    
    #include "errlib.h"
    #include "sockwrap.h"
    
    #define MAXBUFL 255
    #define LISTENQ 15
    #define PORT 1234
    
    
    char *prog;
    
    int main (int argc, char *argv[])
    {
      int listenfd, connfd;
      struct sockaddr_in servaddr, cliaddr;
      socklen_t cliaddrlen = sizeof(cliaddr);
      char buf[MAXBUFL];
    
      uint16_t TRY=0x7ff6;
    
      prog = argv[0];
    
      listenfd = Socket (AF_INET, SOCK_STREAM, 0);
    
      memset (&servaddr, 0, sizeof(servaddr));
      servaddr.sin_family = AF_INET;
      servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
      servaddr.sin_port = htons(PORT);
    
      Bind (listenfd, (SA*) &servaddr, sizeof(servaddr));
    
      Listen (listenfd, LISTENQ);
    
    #ifdef TRACE
      printf ("(%s) socket created, waiting for connections ...\n", prog);
    #endif
    
      for ( ; ; )
      {
        connfd = Accept (listenfd, (SA*) &cliaddr, &cliaddrlen);
    #ifdef TRACE
        printf ("(%s) - new connection from client %s:%u\n", prog, inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
    #endif
    
        TRY=htons(TRY);
    
        Writen (connfd, &TRY,sizeof(TRY));
    
        printf("send: %u dim: %d\n",TRY, sizeof(TRY));
    
        Close (connfd);
      }
    }
    and this is the client:
    Code:
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <string.h>
    #include <stdio.h>
    #include <ctype.h>
    #include <netinet/in.h>
    
    #include "errlib.h"
    #include "sockwrap.h"
    
    #define MAXBUFL 255 
    #define PORT 1234
    
    char *prog;
    
    int main (int argc, char *argv[])
    {
      int sockfd, n,i;
      char buf[MAXBUFL+1];
      struct sockaddr_in servaddr;
      uint16_t try;
      /* for errlib to know the program name */
    
      prog = argv[0];
    
      /* check the arguments */
    
      if (argc != 2)
        err_quit ("usage: %s IPaddress_of_server", prog);
    
      /* create socket */
    
      sockfd = Socket(AF_INET, SOCK_STREAM, 0);
    
      /* specify address of server to connect to */
    
      memset (&servaddr, 0, sizeof(servaddr));
      servaddr.sin_family = AF_INET;
      servaddr.sin_port   = htons(PORT);
      Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
    
      /* try to connect */
    
      Connect (sockfd, (SA*) &servaddr, sizeof(servaddr));
    
      /* read the answer */
      memset(buf,'\0',sizeof(buf));
      while ( (n = Read(sockfd,buf,MAXBUFL)) > 0)
      {
        Write (1, buf, n);
      }
      memcpy(&try,buf,strlen(buf));
      try=ntohs(try);
    
      printf("\n(int)try: %d\ntry: %x \nbuf: %s\nlenght: %d\nsize of buf: %d",(int)try,try,buf,strlen(buf),sizeof(buf));
    
      for(i=0;i<strlen(buf);i++)
      	if(isdigit(buf[i])) printf("\n%d is a number",(int)buf[i]);
      	else printf("\n%c is not a number",buf[i]);
          
      return 0;
    }
    the trouble is that client recives sometimes 7ff6 (the number i'd like to read evrytime) and sometimes f67f (wrong numbuer!!!)
    how do htons() and ntohs() work? what shoul i change in the client or in the server to get always 7ff6?

    another problem is how to "understand" if the recived buffer has got an uint16_t inside (obviously isdigit doesn't work, but i tryed it the same)

    thank you very much and sorry for my bad english
    Last edited by ZaC; 06-25-2008 at 06:07 AM.

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    1. I don't see anything wrong on first glance with your htons and ntohs. I don't do network programming, I'm afraid, so maybe something will jump out at somebody else.

    2. *Any* 16 bits is a valid uint16_t, so as long as you received 16 bits, you have a number.

  3. #3
    FOSS Enthusiast
    Join Date
    Jun 2008
    Posts
    64
    As far as I know, you don't have to use htons() or ntohs() on the data you want to send.
    If you send out data on a TCP stream, it will be received in the same order as you sent it.

    I don't know if its the same when sending integral types because I always use strings, which include a little overhead for better message handling(for instance "<msg><data type='some_type'>DATA</data></msg>").
    This will also decrease the likelyness that someone creates a segfault using telnet, and give your server the ability to distinguish different types of messages (if implemented correctly).

    Anyway, the point is that you don't need to convert the data, because that is handled by lower layers. Just like you don't need to implement confirmation of sent packages, it's also done by TCP.

  4. #4
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by mkruk View Post
    As far as I know, you don't have to use htons() or ntohs() on the data you want to send.
    If you send out data on a TCP stream, it will be received in the same order as you sent it.

    I don't know if its the same when sending integral types because I always use strings, which include a little overhead for better message handling(for instance "<msg><data type='some_type'>DATA</data></msg>").
    This will also decrease the likelyness that someone creates a segfault using telnet, and give your server the ability to distinguish different types of messages (if implemented correctly).

    Anyway, the point is that you don't need to convert the data, because that is handled by lower layers. Just like you don't need to implement confirmation of sent packages, it's also done by TCP.
    Wrong.
    Integer types can be Big Endian or Little Endian on different platforms, so you need to convert it to network byte order before you send it over a network, then back to host order when you receive it.

  5. #5
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    well, the "payload" of the message doesn't necessarily have to be marshalled into the correct byte order so long as the reciever knows how the data is structured. having said that, it is certainly a good idea to send binary in the correct byte order - just not required for the proper delivery of the data.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  6. #6
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Sure, if you only have 2 Intel machines talking to each other, it doesn't matter, but if you have Intel talking to SPARC (or just about anything else), you need to convert it before sending and after receiving.

  7. #7
    Lost in the C ZaC's Avatar
    Join Date
    Jun 2008
    Location
    Italy
    Posts
    47
    thanks for your reply.
    I spot where my test code was wrong!
    TRY=htons(TRY);
    this set TRY to f67f (the right conversion i need) the first time than the second time i make the request TRY will be reconverted in 7ff6 (the "wrong" conversion i don't want).
    htons and ntohs work fine, it was me to be a dummy

    what about checking if what client (the server in my real program) recives is a uint16_t?
    tabspot gives me an excellent answer but i'd like to bilive there is some function to do this...
    if i recive "ca" i would like to send error instead to interpret it as 202

  8. #8
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by ZaC View Post
    what about checking if what client (the server in my real program) recives is a uint16_t?
    tabspot gives me an excellent answer but i'd like to bilive there is some function to do this...
    if i recive "ca" i would like to send error instead to interpret it as 202
    The question becomes, what's wrong with 202? It's unlikely to be characters, I would think. If you know/expect a range of inputs, you can convert and then check.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Trouble with assignment in C
    By mohanlon in forum C Programming
    Replies: 17
    Last Post: 06-23-2009, 10:44 AM
  2. Replies: 6
    Last Post: 01-03-2007, 03:02 PM
  3. Is it so trouble?
    By Yumin in forum Tech Board
    Replies: 4
    Last Post: 01-30-2006, 04:10 PM
  4. trouble scanning in... and link listing
    By panfilero in forum C Programming
    Replies: 14
    Last Post: 11-21-2005, 12:58 PM
  5. C++ program trouble
    By senrab in forum C++ Programming
    Replies: 7
    Last Post: 04-29-2003, 11:55 PM