Thread: reading tcp port raw data always ends after one dataline (noob)

  1. #1
    Registered User
    Join Date
    Jun 2013
    Posts
    5

    reading tcp port raw data always ends after one dataline (noob)

    Hey,

    I'm pretty new to this, had an 'advanced c course' a few years ago and now i'm back into it. Now i got an arduino hooked up to a small pentium 3 management pc with ser2net, local ip 192.168.178.44 at port 420 (421 incase of an error but thats not implemented yet).

    Anyways, i'm pretty new to C and i already did a lot of googling but i'm having a really hard time with this networking related code that im trying to use and understand how to get data from that ip address at that port. I eventually want to (as i progress learning c) set up some nice data graphs or calculate statistics from the raw output of my arduino. It is mangaging an automated airconditioner incase you are wondering.

    It always only retrieves the header symbols of the the beginning of the data stuff:

    Code:
    Received �������� (12 bytes).
    should be like:

    Code:
    ��������
    ser2net port 420 device /dev/ttyACM0 [9600 N81] (Debian GNU/Linux)
    
    
    --2.00 Offthresh: 69.00
    --End Msg Block--
    --Begin Msg Block--
    Avg Press float Sens 97381.00
    Avg Temp float Sens 25.49
    and so on, like a continously repeated list of recent sensor and device states.

    I'm glad for any help

    Code:
    #include <stdio.h>#include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
     
    #define MAXRCVLEN 64000
    #define PORTNUM 420
     
    int main(int argc, char *argv[])
    {
       char buffer[MAXRCVLEN + 1]; /* +1 so we can add null terminator */
       int len, mysocket;
       struct sockaddr_in dest; 
     
       mysocket = socket(AF_INET, SOCK_STREAM, 0);
     
       memset(&dest, 0, sizeof(dest));                /* zero the struct */
       dest.sin_family = AF_INET;
       dest.sin_addr.s_addr = inet_addr("192.168.178.44"); /* set destination IP number */ 
       dest.sin_port = htons(420);                /* set destination port number */
     
    // while (len < MAXRCVLEN)
    //{
       connect(mysocket, (struct sockaddr *)&dest, sizeof(struct sockaddr));
    
    
       len = recv(mysocket, buffer, MAXRCVLEN, 0);
    //}
    //if (len >= MAXRCVLEN)
    //{
       /* We have to null terminate the received data ourselves */
     //  buffer[len] = '\0';
    // }
       printf("Received %s (%d bytes).\n", buffer, len);
     
       close(mysocket);
       return EXIT_SUCCESS;
    }
    (not my code, i'm just trying to learn from it)
    the code comments are just some stuff i messed around with.
    Last edited by milp; 06-06-2013 at 11:24 AM. Reason: kinda wrote a contentless post

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,666
    Perhaps if you have
    Code:
    if (len >= 0 ) {
        buffer[len] = '\0';
        printf("Received %s (%d bytes).\n", buffer, len);
    } else {
      // call perror perhaps to find out why it failed.
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Not sure what you're using for a tutorial, but Beej's guide (link) is one of the best (the best?) out there, IMO. You should also be checking the return value of every socket-related call and reacting accordingly if it fails (e.g. perror, cleanup and exit). Read the docs for each function to find out about return values and error codes.

    If you want to read more than one chunk of data, you should put your read code in a loop. Also note that each call to recv may return less than the desired number of bytes, so if you're expecting 60 bytes in a packet, something like:
    Code:
    len = recv(mysocket, buffer, 60, 0)
    May only return 30 bytes, indicating you need to keep reading until you get a whole packet of sensor data.

    Since you appear to be working with blocking sockets, I recommend a read_n_bytes function that guarantees it reads n bytes or returns with an error, i.e. it wont return with a partial packet. A rough outline goes like this:
    Code:
    int read_n_bytes(int socket, int flags, char *buffer, int num_bytes)
    {
        int bytes_read;  // bytes read in one call to recv
    
        do {
            bytes_read = recv(socket, buffer, num_bytes, 0);
            if (bytes_read > 0) {
                // successful read
                num_bytes -= bytes_read;  // reduce the number of bytes left to read
                buffer += bytes_read;  // increment pointer to where we write data we read
            }
            else if (bytes_read < 0) {
                // read the docs, EINTR is not a regular error, you should just call recv again with the same params
                if (errno == EINTR) {
                    // fake out our loop condition so we try again
                    bytes_read = 1;
                }
            }
        } while (bytes_read > 0 and num_bytes > 0);
    
        return xxxx;  // return some appropriate value, either total bytes read or 0 for succes, or -1 for error, or whatever works for your needs
    }
    Note, that is totally untested and probably not the best implementation, but should give you an idea. Then you would use it like so:
    Code:
    if (read_n_bytes(mysocket, header_info, HEADER_INFO_SIZE, 0) == HEADER_INFO_SIZE) {
        // successful read, read sensor data in a similar manner
    }

  4. #4
    Registered User
    Join Date
    Jun 2013
    Posts
    5
    Quote Originally Posted by Salem View Post
    Perhaps if you have
    Code:
    if (len >= 0 ) {
        buffer[len] = '\0';
        printf("Received %s (%d bytes).\n", buffer, len);
    } else {
      // call perror perhaps to find out why it failed.
    }
    Awesome, thank you!

    I don't know if i implemented perror wrong but it seems there is no error:

    Code:
        if (len >= MAXRCVLEN)
        {
           /* We have to null terminate the received data ourselves */
        buffer[len] = '\0';
         }
        if (len >= 0 ) {
            buffer[len] = '\0';
            printf("Received %s (%d bytes).\n", buffer, len);
        } 
        else
         {
        perror ("The following error occurred"); 
         // call perror perhaps to find out why it failed.
        }
    Code:
    Received �������� (12 bytes).
    Last edited by milp; 06-06-2013 at 12:34 PM.

  5. #5
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    No, that's fine. perror should only be called when recv fails. Since it succeeded in your case, it's not going to print anything.

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,666
    Are you sure you're receiving printable strings (do you have the send() code as well?)

    If it's binary data, %s won't make sense of it.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User
    Join Date
    Jun 2013
    Posts
    5
    Quote Originally Posted by anduril462 View Post
    Not sure what you're using for a tutorial, but Beej's guide (link) is one of the best (the best?) out there, IMO. You should also be checking the return value of every socket-related call and reacting accordingly if it fails (e.g. perror, cleanup and exit). Read the docs for each function to find out about return values and error codes.

    If you want to read more than one chunk of data, you should put your read code in a loop. Also note that each call to recv may return less than the desired number of bytes, so if you're expecting 60 bytes in a packet, something like:
    Code:
    len = recv(mysocket, buffer, 60, 0)
    May only return 30 bytes, indicating you need to keep reading until you get a whole packet of sensor data.

    Since you appear to be working with blocking sockets, I recommend a read_n_bytes function that guarantees it reads n bytes or returns with an error, i.e. it wont return with a partial packet. A rough outline goes like this:
    Code:
    int read_n_bytes(int socket, int flags, char *buffer, int num_bytes)
    {
        int bytes_read;  // bytes read in one call to recv
    
        do {
            bytes_read = recv(socket, buffer, num_bytes, 0);
            if (bytes_read > 0) {
                // successful read
                num_bytes -= bytes_read;  // reduce the number of bytes left to read
                buffer += bytes_read;  // increment pointer to where we write data we read
            }
            else if (bytes_read < 0) {
                // read the docs, EINTR is not a regular error, you should just call recv again with the same params
                if (errno == EINTR) {
                    // fake out our loop condition so we try again
                    bytes_read = 1;
                }
            }
        } while (bytes_read > 0 and num_bytes > 0);
    
        return xxxx;  // return some appropriate value, either total bytes read or 0 for succes, or -1 for error, or whatever works for your needs
    }
    Note, that is totally untested and probably not the best implementation, but should give you an idea. Then you would use it like so:
    Code:
    if (read_n_bytes(mysocket, header_info, HEADER_INFO_SIZE, 0) == HEADER_INFO_SIZE) {
        // successful read, read sensor data in a similar manner
    }
    Thanks a lot, i tried to rewrite the code and include yours but i had a really hard time and in the end i failed to get it to compile, after i had debugged all the errors gcc showed, it would show the output at the bottom of the post when compiling and no output was generated:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
     
    #define MAXRCVLEN 64
    #define PORTNUM 420
     
    int main(int argc, char *argv[])
    {
       char buffer[MAXRCVLEN + 1]; /* +1 so we can add null terminator */
       int len, mysocket;
       struct sockaddr_in dest; 
     
       mysocket = socket(AF_INET, SOCK_STREAM, 0);
     
       memset(&dest, 0, sizeof(dest));                /* zero the struct */
       dest.sin_family = AF_INET;
       dest.sin_addr.s_addr = inet_addr("192.168.178.44"); /* set destination IP number */ 
       dest.sin_port = htons(420);                /* set destination port number */
     
    // while (len < MAXRCVLEN)
    //{
       connect(mysocket, (struct sockaddr *)&dest, sizeof(struct sockaddr));
       len = recv(mysocket, buffer, MAXRCVLEN, 0);
    //}
    if (read_n_bytes(mysocket, 0, MAXRCVLEN, 0) == MAXRCVLEN) 
    	{
    	// successful read, read sensor data in a similar manner
    	printf("Received %s (%d bytes).\n", buffer, len);
    
    
    	}
    	else
     	{
    	perror ("The following error occurred"); 
     	// call perror perhaps to find out why it failed.
    	}	
    //   printf("Received %s (%d bytes).\n", buffer, len);
     //void perror ( const char * str );
       close(mysocket);
       return EXIT_SUCCESS;
    }
    
    
    int read_n_bytes(int socket, int flags, char *buffer, int num_bytes)
    {
        int bytes_read;  // bytes read in one call to recv
     
        while (bytes_read > 0) and (num_bytes > 0);
    	{
            bytes_read = recv(socket, buffer, num_bytes, 0);
            if (bytes_read > 0) 
    		{
                // successful read
                num_bytes -= bytes_read;  // reduce the number of bytes left to read
                buffer += bytes_read;  // increment pointer to where we write data we read
            }
            else
    		{		
    		if (bytes_read < 0) 
    		{
                // read the docs, EINTR is not a regular error, you should just call recv again with the same params
       //         if (errno == EINTR) {
                    
    	// fake out our loop condition so we try again
                    bytes_read = 1;
            }
    		}
            }
    		return bytes_read;
        }
    Code:
    srcds@PCZubu:~/coding........$ gcc 12clientmess.c
    /tmp/ccrC58XP.o: In function `read_n_bytes':
    12clientmess.c:(.text+0x137): undefined reference to `and'
    collect2: ld returned 1 exit status
    I hope i didn't mess this up completely. I'm gonna continue with this tomorrow but for now i need sleep. Would love to see some more helpful answers

  8. #8
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    in read_n_bytes() replace and with &&
    Kurt

  9. #9
    Registered User
    Join Date
    Jun 2013
    Posts
    5
    Thanks

    I got it to compile now but the program returns the following error when i start it:

    srcds@PCZubu:~/coding........$ ./a.out
    The following error occurred: Transport endpoint is not connected
    Please help me, i kinda feel dumb but the stuff i find on google about this doesn't really tell me anything. In the meantime i'll take a look at beej's guide.

    Man this is really messing with my brains but at the same time it's so exciting. Also thank you all for your great support so far!

  10. #10
    Registered User
    Join Date
    Dec 2007
    Posts
    2,675
    From post #3:

    Not sure what you're using for a tutorial, but Beej's guide (link) is one of the best (the best?) out there, IMO. You should also be checking the return value of every socket-related call and reacting accordingly if it fails (e.g. perror, cleanup and exit). Read the docs for each function to find out about return values and error codes.
    With added emphasis.

  11. #11
    Registered User hex_dump's Avatar
    Join Date
    Dec 2012
    Posts
    88
    Quote Originally Posted by milp View Post
    Thanks

    I got it to compile now but the program returns the following error when i start it:



    Please help me, i kinda feel dumb but the stuff i find on google about this doesn't really tell me anything. In the meantime i'll take a look at beej's guide.

    Man this is really messing with my brains but at the same time it's so exciting. Also thank you all for your great support so far!
    is your arduino connected to external power supply? googled it and that was what I found so you may want to make sure of that.

  12. #12
    Registered User
    Join Date
    Jun 2013
    Posts
    5
    Quote Originally Posted by hex_dump View Post
    is your arduino connected to external power supply? googled it and that was what I found so you may want to make sure of that.
    Yes, the technical side is fine. Otherwise i think nc 192.168.178.44 420 wouldn't work either, but it outputs the data flawlessly:

    Code:
    srcds@PCZubu:~$ nc 192.168.178.44 420
    ��������
    ser2net port 420 device /dev/ttyACM0 [9600 N81] (Debian GNU/Linux)
    
    
    DH-End Msg Block--
     0.00 Onthresh: 26.00 Offthresh: 25.00
    Humidifier Online. Humidmode: 1.00 Onthresh: 62.00 Offthresh: 69.00
    --End Msg Block--
    --Begin Msg Block--
    Avg Press float Sens 97293.00
    Avg Temp float Sens 25.20
    DHT11/BMP Temp: 24.50
     BMP temp: 25.20
     DHT11 Humid: 66.60
    Temperature higher than Heatthresh, not Heating.
    Vent. System normal operation. Fan12 Mode:0.00 Onthresh: 25.00 Offthresh:24.00
     Humidoff: 42.00
     TooHighHumidThresh: 48.00
    Air Conditioner Online, ACmode: 0.00 Onthresh: 26.00 Offthresh: 25.00
    Humidifier Online. Humidmode: 0.00 Onthresh: 62.00 Offthresh: 69.00
    --End Msg Block--

  13. #13
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Quote Originally Posted by anduril462 View Post
    Code:
    int read_n_bytes(int socket, int flags, char *buffer, int num_bytes)
    Note, that is totally untested and probably not the best implementation, but should give you an idea. Then you would use it like so:
    Code:
    if (read_n_bytes(mysocket, header_info, HEADER_INFO_SIZE, 0) == HEADER_INFO_SIZE) {
        // successful read, read sensor data in a similar manner
    }
    Quote Originally Posted by milp View Post
    Code:
    if (read_n_bytes(mysocket, 0, MAXRCVLEN, 0) == MAXRCVLEN)
    anduril462 mixed up the order of the arguments in the example call. The second parameter is some flags, the third the buffer and the fourth the number of bytes to read.

    Code:
    int read_n_bytes(int socket, int flags, char *buffer, int num_bytes)
    {
        int bytes_read;  // bytes read in one call to recv
     
        while (bytes_read > 0) and (num_bytes > 0);
    anduril462 used a do-while loop on purpose.
    And you would need to use another set of parentheses around both conditions and remove the semicolon at the end of the line.

    Bye, Andreas

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Error while reading data from serial port
    By Saad Rafey in forum Windows Programming
    Replies: 3
    Last Post: 02-28-2013, 12:20 AM
  2. Error while reading data from serial port
    By Saad Rafey in forum C++ Programming
    Replies: 1
    Last Post: 02-28-2013, 12:13 AM
  3. Serial port reading data
    By saikgr in forum C Programming
    Replies: 6
    Last Post: 12-07-2012, 07:57 AM
  4. Reading image data from COM7 port
    By stud91 in forum Networking/Device Communication
    Replies: 1
    Last Post: 04-11-2012, 09:48 PM
  5. accessing my com port, writing and reading data
    By shoobsie in forum C Programming
    Replies: 7
    Last Post: 09-16-2005, 03:29 PM