Use of the libevent library a working instance of the timer

  • 2020-04-02 02:04:46
  • OfStack


#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <event.h>
#include <evhttp.h>
#define RELOAD_TIMEOUT 5
#define DEFAULT_FILE "sample.html"
char *filedata;
time_t lasttime = 0;
char filename[80];
int counter = 0;
void read_file()
{
  int size = 0;
  char *data;
  struct stat buf;
  stat(filename,&buf);
  if (buf.st_mtime > lasttime)
    {
      if (counter++)
        fprintf(stderr,"Reloading file: %s",filename);
      else
        fprintf(stderr,"Loading file: %s",filename);
      FILE *f = fopen(filename, "rb");
      if (f == NULL)
        {
          fprintf(stderr,"Couldn't open filen");
          exit(1);
        }
      fseek(f, 0, SEEK_END);
      size = ftell(f);
      fseek(f, 0, SEEK_SET);
      data = (char *)malloc(size+1);
      fread(data, sizeof(char), size, f);
      filedata = (char *)malloc(size+1);
      strcpy(filedata,data);
      fclose(f);

      fprintf(stderr," (%d bytes)n",size);
      lasttime = buf.st_mtime;
    }
}
void load_file()
{
  struct event *loadfile_event;
  struct timeval tv;
  read_file();
  tv.tv_sec = RELOAD_TIMEOUT;
  tv.tv_usec = 0;
  loadfile_event = malloc(sizeof(struct event));
  evtimer_set(loadfile_event,
              load_file,
              loadfile_event);
  evtimer_add(loadfile_event,
              &tv);
}
void generic_request_handler(struct evhttp_request *req, void *arg)
{
  struct evbuffer *evb = evbuffer_new();
  evbuffer_add_printf(evb, "%s",filedata);
  evhttp_send_reply(req, HTTP_OK, "Client", evb);
  evbuffer_free(evb);
}
int main(int argc, char *argv[])
{
  short          http_port = 8081;
  char          *http_addr = "192.168.0.22";
  struct evhttp *http_server = NULL;
  if (argc > 1)
    {
      strcpy(filename,argv[1]);
      printf("Using %sn",filename);
    }
  else
    {
      strcpy(filename,DEFAULT_FILE);
    }
  event_init();
  load_file();
  http_server = evhttp_start(http_addr, http_port);
  evhttp_set_gencb(http_server, generic_request_handler, NULL);
  fprintf(stderr, "Server started on port %dn", http_port);
  event_dispatch();
}

The rationale for this server is the same as in the previous example. First, the script sets up an HTTP server that only responds to requests for the base URL host/port combination (it does not process the request URI). The first step is to load the file(read_file()). This function is used when the original file is loaded and when the timer triggers a callback.
The read_file() function USES the stat() function call to check the modification time of the file, and only re-reads the contents of the file if the file was modified after the last load. This function loads the file data by calling fread(), copies the data into another structure, and then USES strcpy() to transfer the data from the loaded string to the global string.
The load_file() function is the function that is called when the timer is fired. It loads the content by calling read_file(), and then sets the timer with the RELOAD_TIMEOUT value as the number of seconds before attempting to load the file. The libevent timer USES the timeval structure, allowing timers to be specified in seconds and milliseconds. The timer is not periodic; Set the timer event when it fires, and then delete the event from the event queue.
Compile the code in the same format as the previous example: $gcc-o basichttpfile basichttpfile.c-levent.
Now, create a static file to be used as data; The default file is sample.html, but you can specify any file with the first argument on the command line (see listing 6).
Listing 6. Create a static file to be used as data


$ ./basichttpfile
Loading file: sample.html (8046 bytes)
Server started on port 8081

Now the program is ready to accept the request, and the reload timer starts. If you modify the contents of sample.html, the file should be reloaded and a message logged. For example, the output in listing 7 shows the initial load and two reloads:
Listing 7. The output shows the initial load and two reloads


$ ./basichttpfile
Loading file: sample.html (8046 bytes)
Server started on port 8081
Reloading file: sample.html (8047 bytes)
Reloading file: sample.html (8048 bytes)

Note that for maximum benefit, you must ensure that the environment does not limit the number of file descriptors open. You can use the ulimit command to modify the limit (requiring appropriate permissions or root access). The specific Settings depend on your OS, but in Linux® The number of open file descriptors (and network sockets) can be set with the -n option on


Related articles: