0
votes

I have an MCU unit that is connected to the local network. This device is sending it's status data over a TCP socket 100 times per second. Over the same socket I can also issue commands and data.

I'm trying to write a simple TCP client that could connect to the device, grab the data and if requested send commands. Currently I can send commands without problems (the commands are sent as strings and this works). My problem is reception of the data FROM device.

I know from the device manual that the data should be a 32 bit integer first, then an array of approximately 30 doubles)

I am establishing a new thread that I want to contineously intercept the data and process it:

void *com::setListenerSocket(void* threadSocketData) {
        struct socketData *sockData;
        sockData = (socketData*)threadSocketData;
        com::tcp_client cListener;

        struct timeval timeout;
        timeout.tv_sec=0;
        timeout.tv_usec=12500;

    //  setsockopt(cListener, IPPROTO_TCP, SO_RCVTIMEO, (char *)timeout, sizeof(timeout)); //no effect
        cListener.connect(sockData->host , sockData->port);
        cout << "listener thread started" << endl;
        cout << "host=" << sockData->host << " at port=" << sockData->port << endl;

        cListener.send_data("Listener Reporting\n");
    while(listenerRun){
        listenerHB++;
        cout << endl <<"*****************************       BGN     *************************************************************"<< endl;
        char *received = new char[PACKETSIZE];
        cListener.receive(PACKETSIZE, received);
        unsigned int test;
        test = (uint32_t) received;
        cout << "received=" << test << endl;
        for(int i = 0; i< PACKETSIZE ; ++i)
          cout << received[i] << ", ";
        cout << endl <<"*****************************       END     *********************************************"<< endl;
        robotPacket data;
        //parseData(received, &data);
        //usleep(1 MS);
    }
    cout << "listener signing out" << endl;;
    pthread_exit(NULL);
}

and the listener method is:

void com::tcp_client::receive(int size, char* buffer) {

  unsigned int bytecnt = 0, archive = 1;

  while(bytecnt < (unsigned int)size) {
//     bytecnt += recv(sock , &buffer[bytecnt] , size-bytecnt , 0); 
    bytecnt += recv(sock , buffer , size-bytecnt , MSG_WAITALL); 
  }

  unsigned int test;
  test = buffer[0];
  cout << "value=" << test << "¤" << endl;
  }

I took the pointer to the beginning of the buffer and cast it to uint32_t, but the result is completely wrong (I know it should be packet length, but it goes into millions of millions easily)

When I use the nl command: nc -l 12354 I can write text to my program and everything is correct

EDIT: Had a meeting with someone more experienced: SOLVED: I can't post solution myself, so I'll put it in here in case someone encounters a similar problem.

First of all, I expected the socket to be automatically handling where is a single transmission begin and where is its end - which is not true, as Basyle Starynkevitch pointed. However, the TCP ensures the data is coming in sequence and nothing is lost so I can safely assume that for 500 bytes promised I will get that 500 bytes or whatever it is.

Secondly, the data is coming in in the big endian - also as pointed by Basyle. I did a bit of bit shifting but still had a wrong result but...

Finally, I had another problem with type casting. I was using char* while the data is an unsigned char. Replacing buffers char* with unsigned char* solved the decoding issue.

This can be solution for anyone who gets to interface with old electronic devics that communicate over the local area network.

I guess this case can be considered closed if someone posts what I wrote above in a neat form.

1
recv can fail with a negative bytecntBasile Starynkevitch
if (probe = recv(sock , buffer , size-bytecnt , MSG_WAITALL) > 0)bytecnt += probe; Now the data comes in much slower, but the first integer is still insane... What can cause negative bytecnt?user3002166
Read recv(2). And you need to understand precisely the protocol you are implementing. Worry about endianness. See htonl(3) and endian(3)Basile Starynkevitch
Is it possible, that my socket connection starts to listen in the middle of the packet fills up with an other half of the packet and gets corrupted in that way? Can a socket client detect when is the new packet beginning?user3002166
On the application side, TCP has no notion of packets (it is just a byte stream). See Nagle's algorithm & this answer.Basile Starynkevitch

1 Answers

0
votes

You may want to check out tcpclient (http://cr.yp.to/ucspi-tcp/tcpclient.html). You can simply run your C/C++ program under tcpclient - i.e. tcpclient will spawn your program and open an tcp connection to the server, and pipe your program's stdout to the server, and pipe output from the server to your program's stdin. The nice thing about doing it this way is that you can let tcpclient to all the heavy lifting as far as setting up the socket, etc., and you can focus on the core function of your program.