Search code examples
cmultithreadingsocketstcp

How can I make the program read sensors every 10 milliseconds while the tcp server is waiting for data


My program need to read sensor data every 10 milliseconds, and send it to client by TCP socket. The program is written in C language. The tcp server and sensor reading codes are in the same c file. The server doesn't send data periodically. Instead, it waits for the data request (every 50 milliseconds) from the client. Once the server receives the request, it sends data to client.

My problem is that I need to read sensors every 10 milliseconds and save it in a buffer. Once the server get the request, send the sensor data in the buffer to client. But when tcp server is waiting for the request, the whole program stuck at the read function:

n = read(newsockfd,buffer,31)

Then, I can't read sensors.

I tried to use threading for sensor reading and tcp server. It works for reading sensors. But, if I add any usleep(), for example, 5 milliseconds in tcp server thread, it will take 5 milliseconds before sending data to the client.

My program need the tcp server send data to client immediately after it receives the request. Meanwhile, read sensors every 10 milliseconds. Anyone has a better solution?

The codes for tcp server and sensor reading are as follows:

#include <stdio.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>

#define MAX_SIZE 256
#define SAMPLE_RATE 



void read_sensor(void) {
    printf("read sensors\n");
}


int main() {

     int sockfd, newsockfd, portno = 10000, clilen;
     char buffer[MAX_SIZE];
     struct sockaddr_in serv_addr, cli_addr;
     int n;
     int data;

     printf( "using port #%d\n", portno );

     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     if (sockfd < 0) 
         printf("ERROR opening socket\n");
     bzero((char *) &serv_addr, sizeof(serv_addr));

     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons( portno );
     if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
       error( const_cast<char *>( "ERROR on binding" ) );
     listen(sockfd,5);
     clilen = sizeof(cli_addr);

     while (1) {
        printf( "waiting for new client...\n" );
        if ( ( newsockfd = accept( sockfd, (struct sockaddr *) &cli_addr, (socklen_t*) &clilen) ) < 0 )
            printf("ERROR on accept");
        printf( "opened new communication with client\n" );

        clock_gettime(CLOCK_REALTIME, &gettime_now);
        start_time = gettime_now.tv_nsec;       //Get nS value
        while (1) {
             int n = 0;
             if ( (n = read(newsockfd,buffer,31) ) < 0 ) //read data
                printf("ERROR reading from socket");
             buffer[n] = '\0';

             if (n > 0)
                printf("%s\n", buffer);
             else {
                break;             
             }

             if ( (n = write( newsockfd, buffer, strlen(buffer) ) ) < 0 ) //send data
                printf( "ERROR writing to socket\n");
             buffer[n] = '\0';

        }
        close( newsockfd );
     }


     return 0; 
}

Solution

  • You can use select or poll to wait for data to arrive, with a timeout.

    For instance, if you need to read the sensor 5 milliseconds from now, you can call poll or select with a 5 millisecond timeout. If the socket receives data, it will return immediately and tell you. Otherwise, it will return after 5 milliseconds and you'll know there is no data.

    Example with poll:

    struct pollfd pollfd = {.fd = socket_fd, .events = POLLIN};
    int err = poll(&pollfd, 1, milliseconds_timeout);
    // error check here; if err is negative then the error code is in errno
    if (pollfd.revents & POLLIN) {
        // Socket received data
    }
    // Otherwise it didn't.
    // Note that if data was received, it might not be time to read the sensors yet.
    // You should keep poll()ing until it's the right time to read the sensors, using clock_gettime to check the time.