Re: Event loop



On Mon, 13 Nov 2000, Henri Torgemane wrote:

Ok ok, I probably shouldn't help keeping this thread alive, but I'm wondering
something, and I'm sure pretty you guys can enlighten me:

Yes. I can enlighten you. ;-)


Glib offers a pretty cool loop to deal with events, including stuff to
monitor IO activity. Now if I want to write a server application that does a
whole lot of network processing, it's kinda tempting to make all my IO
asynchronous, plug them to Glib and have everything work in one big happy
process.

Glib is nice to make everything cool and simple. But you can do your own
stuff.
 
My question is: Is there any drawback with that approach? Would I be better
off forking or spawning threads to deal with pieces of the network logic
separately (which is sort of the "traditional" unix server design) ?

For higest possible performance you should do something like this...

Just compile and enjoy... ;-)

(Note: Hardwired port to listen to)
----<cut>-----------------------------------------------------
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <err.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


main()
{

  struct protoent *tp = getprotobyname("tcp");
  int serv_sock;  /* Master socket for server */
  fd_set ifds;
  int maxfd;
  struct sockaddr_in sin;
  char **hostnames = NULL;
  

  /* Create TCP socket */
  if( tp == NULL) err(1, "Cannot get tcp trotocol\n");
  serv_sock = socket(PF_INET, SOCK_STREAM, tp->p_proto);
  if( serv_sock < 0)
    err(2, "Cannot create socekt: %s\n", strerror(errno));
  /* Bind the socket to port */
  memset(&sin, 0, sizeof(sin));
  sin.sin_len = sizeof(sin);
  sin.sin_family = PF_INET;

  sin.sin_port = htons(12345);   /* Hardwired port to listen to!!! */

  sin.sin_addr.s_addr = htonl(INADDR_ANY);
  if( bind(serv_sock, (struct sockaddr*)&sin, sizeof(sin)) < 0 )
    err(3, "Cannot bind socket: %s\n", strerror(errno));

  /* Allow incomming connections */
  if( listen(serv_sock, 64) < 0 )   /* 64 is a kernel limit */
    err(3, "Cannot listen to socket: %s\n", strerror(errno));

  FD_ZERO(&ifds);
  FD_SET(serv_sock, &ifds );
  maxfd = serv_sock;

  for(;;) {
    int fd = -1;
    int i;
    struct timeval to = { 2, 0 };

    fd_set tifds = ifds;
    int numfds = select( maxfd+1, &tifds, NULL, NULL, &to);
    if ( numfds == -1 ) err(4, "Cannot select: %s\n", strerror(errno));
    if ( numfds == 0 ) continue;

    /* Find the first connection with input */
    fd = -1;
    for( i = 0; i <= maxfd ; i++ )
      if( FD_ISSET(i, &tifds)) {
        fd = i;
        break;
      }

    if ( fd == -1) err(5, "Oops");
    if ( fd == serv_sock ) {  /* New connection request */
      struct sockaddr_in remote;
      int len = sizeof(remote);
      int rfd;

      /* Accept the connection */
      rfd = accept(serv_sock, (struct sockaddr*)&remote, &len);
      printf("Remote file descriptor %d \n", rfd );

      if (rfd == -1 ) err(6, "Cannot accept: %s\n", strerror(errno));

      printf("Connection from %s \n", inet_ntoa(remote.sin_addr));

      /* Add the new connection to file descriptors to watch */
      FD_SET(rfd, &ifds);
      if( hostnames && rfd < maxfd && hostnames[rfd]) {
        free(hostnames[rfd]);
        hostnames[rfd] = strdup(inet_ntoa(remote.sin_addr));

      } else { 
        maxfd = rfd;

        hostnames = realloc(hostnames, (maxfd+1)*sizeof(char*));
        hostnames[rfd] = strdup(inet_ntoa(remote.sin_addr));

      }
    } else {
      char buf[80];
      int count;
      char *h = hostnames[fd];

      /* Get the input */
      count = read(fd, buf, sizeof(buf));
      if ( count == 0 ) FD_CLR(fd, &ifds);
      else {

        /* Relay the input to every other */
        int i;
        system("ls");
        for ( i = 0 ; i <= maxfd; i++ ) {
          if ( FD_ISSET(i, &ifds) && i != serv_sock && i != fd ) {
            write(i, h, strlen(h));
            write(i, ": ", 2);
            write(i, buf, count);
          }
        }
      }
    }

  }

  printf("The job is done.\n");

}

---<end cut>-------------------------------------------------------


I'm under the impression using Glib that way is efficient since it doesn't
have any of the overhead threading of forking would incur..
Everything gets processed sequentially, but it's exactly what would happen if
things were threaded anyway (assuming only one processor in the box)

On the other side, Glib was written to be used with a graphic toolkit, not
with a network intensive program, and while its implementation seems to be
pretty efficient, one can wonder if it's the right tool for the job. Also I
haven't really heard of any other server out there based on Glib..

What do you guys think?

I think that you should play with select (or poll).

G Hasse

----------------------------------------------------------------
Göran Hasse            email: gh raditex se     Tel: 08-6949270
Raditex AB             http://www.raditex.se    Fax: 08-6949280
Sickla Alle 7, 1tr                              Mob: 070-5530148
131 34  NACKA, SWEDEN






[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]