LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   EPOLL echo server not concurrent (https://www.linuxquestions.org/questions/programming-9/epoll-echo-server-not-concurrent-863144/)

Lantzvillian 02-16-2011 03:05 PM

EPOLL echo server not concurrent
 
Hi all,

I am working on an epoll version of an echoserver that I am porting from a multithreaded version I wrote.

What it should do:
The server should get a connection from a client > say x client connected > print x message from said client.

What it is doing:
The server looks like it is only accepting one connection at a time, and any other clients are queued. When the queue is empty it looks like the program is aborting with a SIGABRT.

EDIT:// fixed the program exiting in the close function. Still one client at a time :(

Any suggestions?

Code:

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#include <strings.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>

#define TRUE                1
#define FALSE                0
#define EPOLL_QUEUE_LEN 10
#define BUFLEN                1024
#define SERVER_PORT        7000

//Globals
int fd_server;

struct clientStuff
{
  int sockfd;
  struct sockaddr_in client;
};

// Function prototypes
static void SystemFatal (const char* message);
static void* ClearSocket (void* arg);
void close_fd (int);

int main (int argc, char* argv[])

  int i, arg, visits;
  int num_fds, fd_new, epoll_fd;
  static struct epoll_event events[EPOLL_QUEUE_LEN], event;
  int port = SERVER_PORT;
  struct sockaddr_in addr, remote_addr;
  socklen_t addr_size = sizeof(struct sockaddr_in);
  struct sigaction act;
  FILE *fp;
  visits =  0;

  // set up the signal handler to close the server socket when CTRL-c is received
  act.sa_handler = close_fd;
  act.sa_flags = 0;
  if ((sigemptyset (&act.sa_mask) == -1 || sigaction (SIGINT, &act, NULL) == -1))
  {
    perror ("Failed to set SIGINT handler");
    exit (EXIT_FAILURE);
  }
 
  // Create the listening socket
  fd_server = socket (AF_INET, SOCK_STREAM, 0);
  if (fd_server == -1)
    SystemFatal("socket");
 
  // set SO_REUSEADDR so port can be resused imemediately after exit, i.e., after CTRL-c
  arg = 1;
  if (setsockopt (fd_server, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) == -1)
    SystemFatal("setsockopt");
 
  // Make the server listening socket non-blocking
  if (fcntl (fd_server, F_SETFL, O_NONBLOCK | fcntl (fd_server, F_GETFL, 0)) == -1)
    SystemFatal("fcntl");
 
  // Bind to the specified listening port
  memset (&addr, 0, sizeof (struct sockaddr_in));
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = htonl(INADDR_ANY);
  addr.sin_port = htons(port);
  if (bind (fd_server, (struct sockaddr*) &addr, sizeof(addr)) == -1)
    SystemFatal("bind");
 
  // Listen for fd_news; SOMAXCONN is 128 by default
  if (listen (fd_server, SOMAXCONN) == -1)
    SystemFatal("listen");
 
  // Create the epoll file descriptor
  epoll_fd = epoll_create(EPOLL_QUEUE_LEN);
  if (epoll_fd == -1)
    SystemFatal("epoll_create");
 
  // Add the server socket to the epoll event loop
  event.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLET;
  event.data.fd = fd_server;
  if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, fd_server, &event) == -1)
    SystemFatal("epoll_ctl");
 
  // Execute the epoll event loop
  while (TRUE)
  {
    // signal( SIGABRT, function);
    //struct epoll_event events[256];
    num_fds = epoll_wait (epoll_fd, events, EPOLL_QUEUE_LEN, -1);
    if (num_fds < 0)
      SystemFatal ("Error in epoll_wait!");
   
    for (i = 0; i < num_fds; i++)
    {
      // Case 1: Error condition
      if (events[i].events & (EPOLLHUP | EPOLLERR))
      {
        fputs("epoll: EPOLLERR", stderr);
        close(events[i].data.fd);
        continue;
      }
      assert (events[i].events & EPOLLIN);
     
      // Case 2: Server is receiving a connection request
      if (events[i].data.fd == fd_server)
      {
        struct clientStuff c1;

        fd_new = accept (fd_server, (struct sockaddr*) &remote_addr, &addr_size);
       
          printf(">> Initializing remote address: %s\n", inet_ntoa(remote_addr.sin_addr));
         
          visits++;
         
          fp=fopen("server-output.txt", "a"); /* Open file */
          fprintf(fp, "Connections-to-date,%u\n",visits);
          fprintf(fp, "%s,connect\n",inet_ntoa(remote_addr.sin_addr));
          fclose(fp);
         
          printf("Connections to date: %u \n",visits);         

        c1.sockfd = fd_new;
        printf("sockfd: %u\n",c1.sockfd);
        c1.client = remote_addr;
       
        if (fd_new == -1)
        {
          if (errno != EAGAIN && errno != EWOULDBLOCK)
          {
            perror("accept");
          }
          continue;
        }
       
        // Make the fd_new non-blocking
        if (fcntl (fd_new, F_SETFL, O_NONBLOCK | fcntl(fd_new, F_GETFL, 0)) == -1)
          SystemFatal("fcntl");
       
        // Add the new socket descriptor to the epoll loop
          event.data.fd = fd_new;
          if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, fd_new, &event) == -1)
            SystemFatal ("epoll_ctl");
         
          continue;
      }
     
      // Case 3: One of the sockets has read data
      if (!ClearSocket(events[i].data.fd))
      {
        // epoll will remove the fd from its set
        // automatically when the fd is closed
        close (events[i].data.fd);
      }
    }
  }
  close(fd_server);
  exit (EXIT_SUCCESS);
}



static void* ClearSocket (void* arg)
{
 struct clientStuff *ptr;
  struct sockaddr_in client_addr;
  int bytes_to_read, sockfd;
  char *bp, buf[BUFLEN];
  ssize_t n;
  FILE *fp;
 
  //ptr = (struct clientStuff *)arg;

  sockfd = (int) arg;
    //printf("sockfd: %u",ptr->sockfd);
 // client_addr = ptr->client;
  bp = buf;
  bytes_to_read = BUFLEN -1;
 
  while(1) {
    n = read(sockfd, bp, bytes_to_read);
   
      bp += n;
      bytes_to_read -= n;
     
      if (bytes_to_read <= 0)
      {
        /* File I/O Preparations */
        fp=fopen("server-output.txt", "a");
        fprintf(fp,"%s,Recv,%s\n",inet_ntoa(client_addr.sin_addr), buf);       
        printf("%s,Recv,%s\n", inet_ntoa(client_addr.sin_addr), buf);
      }
      if((write(sockfd, "DATA-ACK", strlen("DATA-ACK"))) == -1) {
          fprintf(fp, "%s,Disconnect\n",inet_ntoa(client_addr.sin_addr));
          fclose(fp);
          printf("Error on read\n");
          close(sockfd);
          return 1;
      }
     
      fprintf(fp, "%s,Sent,DATA-ACK\n",inet_ntoa(client_addr.sin_addr));
      fclose(fp);
      sleep(9);
   
  }
  return 1;
}

// Prints the error stored in errno and aborts the program.
static void SystemFatal(const char* message)
{
  perror (message);
  exit (EXIT_FAILURE);
}

// close fd
void close_fd (int signo)
{
  close(fd_server);
  exit (EXIT_SUCCESS);
}


dwhitney67 02-17-2011 01:10 PM

You have a mess in ClearSocket().

1. Why is the function parameter declared as a void pointer? Declare it as an int, and thus mitigating the need to cast it at a later time.

2. Since you have setup your client socket as non-blocking, you need to pay careful attention to the return value from read(). If it returns -1 (which happens often), then you are incrementing bytes_to_read. It will take a long time for it to ever reach 0, especially with the sleep(9) at the end. And btw, why is there a sleep() call?

3. When you write() data, don't assume that you will be successful in writing all the bytes at one instant. Check the return value!

4. Unless the write() fails, there is no way out of the while(1) loop.

Since you posted your query yesterday, it is quite probable that by now you have fixed all of these issues.


P.S. Your code comments indicate that when the client socket is closed, that the socket descriptor is automatically removed from the epoll events list. Are you sure about this? I could not find any documentation to back this up.

Lantzvillian 02-17-2011 04:09 PM

hey dwhitney67,

No I haven't gotten all of my issues out of the way. I have a couple of your points fixed, but I am still being blocked I think.

The reason for the sleep(9) is that the client sends a packet every 9 seconds or so and it keeps the connection open. If I don't have a sleep it will print out the buffer x times and sends a reset closing the comms to the client.

Here is my updated server:
Code:

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#include <strings.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>

#define TRUE                1
#define FALSE                0
#define EPOLL_QUEUE_LEN 10000
#define BUFLEN                1024
#define SERVER_PORT        7000

//Globals
int fd_server;

struct clientStuff
{
  int sockfd;
  struct sockaddr_in client;
};

// Function prototypes
static void SystemFatal (const char* message);
static int ClearSocket (void* arg);
void close_fd (int);

int main (int argc, char* argv[])

  int i, arg, visits,num_fds, fd_new, epoll_fd;
  static struct epoll_event events[EPOLL_QUEUE_LEN], event;
  int port = SERVER_PORT;
  struct sockaddr_in addr, remote_addr;
  socklen_t addr_size = sizeof(struct sockaddr_in);
  struct sigaction act;
  FILE *fp;
  visits =  0;
 
  // set up the signal handler to close the server socket when CTRL-c is received
  act.sa_handler = close_fd;
  act.sa_flags = 0;
  if ((sigemptyset (&act.sa_mask) == -1 || sigaction (SIGINT, &act, NULL) == -1))
  {
    perror ("Failed to set SIGINT handler");
    exit (EXIT_FAILURE);
  }
 
  // Create the listening socket
  fd_server = socket (AF_INET, SOCK_STREAM, 0);
  if (fd_server == -1)
    SystemFatal("socket");
 
  // set SO_REUSEADDR so port can be resused imemediately after exit, i.e., after CTRL-c
    arg = 1;
    if (setsockopt (fd_server, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) == -1)
      SystemFatal("setsockopt");
   
    // Make the server listening socket non-blocking
      if (fcntl (fd_server, F_SETFL, O_NONBLOCK | fcntl (fd_server, F_GETFL, 0)) == -1)
        SystemFatal("fcntl");
     
      // Bind to the specified listening port
        memset (&addr, 0, sizeof (struct sockaddr_in));
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        addr.sin_port = htons(port);
        if (bind (fd_server, (struct sockaddr*) &addr, sizeof(addr)) == -1)
          SystemFatal("bind");
       
        // Listen for fd_news; SOMAXCONN is 128 by default
          if (listen (fd_server, SOMAXCONN) == -1)
            SystemFatal("listen");
         
          // Create the epoll file descriptor
            epoll_fd = epoll_create(EPOLL_QUEUE_LEN);
            if (epoll_fd == -1)
              SystemFatal("epoll_create");
           
            // Add the server socket to the epoll event loop
            event.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLET;
            event.data.fd = fd_server;
            if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, fd_server, &event) == -1)
              SystemFatal("epoll_ctl");
           
            // Execute the epoll event loop
          while (TRUE)
          {
            num_fds = epoll_wait (epoll_fd, events, EPOLL_QUEUE_LEN, -1);
            if (num_fds < 0)
              SystemFatal ("Error in epoll_wait!");
           
            for (i = 0; i < num_fds; i++)
            {
              struct clientStuff c1;
              // Case 1: Error condition
              if (events[i].events & (EPOLLHUP | EPOLLERR))
              {
                fputs("epoll: EPOLLERR", stderr);
                close(events[i].data.fd);
                continue;
              }
              assert (events[i].events & EPOLLIN);
             
              // Case 2: Server is receiving a connection request
              if (events[i].data.fd == fd_server)
              {
                fd_new = accept (fd_server, (struct sockaddr*) &remote_addr, &addr_size);
               
                printf(">> Initializing remote address: %s\n", inet_ntoa(remote_addr.sin_addr));
               
                visits++;
               
                fp=fopen("server-output.txt", "a"); /* Open file */
                fprintf(fp, "Connections-to-date,%u\n",visits);
                fprintf(fp, "%s,connect\n",inet_ntoa(remote_addr.sin_addr));
                fclose(fp);
               
                printf("Connections to date: %u \n",visits);         
        c1.sockfd = fd_new;
          c1.client = remote_addr;
               
                if (fd_new == -1)
                {
                  if (errno != EAGAIN && errno != EWOULDBLOCK)
                  {
                    perror("accept");
                  }
                  continue;
                }
               
                // Make the fd_new non-blocking
                if (fcntl (fd_new, F_SETFL, O_NONBLOCK | fcntl(fd_new, F_GETFL, 0)) == -1)
                  SystemFatal("fcntl");
               
                // Add the new socket descriptor to the epoll loop
                  event.data.fd = fd_new;
                  if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, fd_new, &event) == -1)
                    SystemFatal ("epoll_ctl");
                 
                  continue;
              }
             
              // Case 3: One of the sockets has read data
              if (!ClearSocket(&c1))
              {
                // epoll will remove the fd from its set
                // automatically when the fd is closed
                close(events[i].data.fd);
              }
            }
          }
          close(fd_server);
          exit (EXIT_SUCCESS);
}


/*
 * Function that contains the work for every client
 */
static int ClearSocket (void* arg)
{
  struct clientStuff *ptr;
  struct sockaddr_in client_addr;
  int bytes_to_read, sockfd;
  char *bp, buf[BUFLEN];
  ssize_t n;
  FILE *fp;
 
 // sockfd = arg;
 
    ptr = (struct clientStuff *)arg;
  sockfd = ptr->sockfd;
  client_addr = ptr->client;
 
  bp = buf;
  bytes_to_read = BUFLEN -1;
 
  while(1) {
    if((n = read(sockfd, bp, bytes_to_read)) == -1) {
      printf("read-error");
      //return 1;
  }
   
    bp += n;
    bytes_to_read -= n;
   
    if (bytes_to_read <= 0)
    {
      /* File I/O Preparations */
      fp=fopen("server-output.txt", "a");
      fprintf(fp,"%s,Recv,%s\n",inet_ntoa(client_addr.sin_addr), buf);       
      printf("%s,Recv,%s\n", inet_ntoa(client_addr.sin_addr), buf);
      //continue;
    }
    if((write(sockfd, "DATA-ACK", strlen("DATA-ACK"))) == -1) {
      fprintf(fp, "%s,Disconnect\n",inet_ntoa(client_addr.sin_addr));
      fclose(fp);
      printf("Error on read\n");
      close(sockfd);
      return 0;
    }
   
    //    fprintf(fp, "%s,Sent,DATA-ACK\n",inet_ntoa(client_addr.sin_addr));
    fclose(fp);
    sleep(9);
    //return 0;
   
  }
  return 1;
}

/*
 * Prints the error stored in errno and aborts the program.
 */
static void SystemFatal(const char* message)
{
  perror (message);
  exit (EXIT_FAILURE);
}

/*
 * close fd
 */
void close_fd (int signo)
{
  close(fd_server);
  //exit (EXIT_SUCCESS);
}

Here is the client in case you want to compile it.. it is ran with ./client.o address 0 yourMessage
0 means send unlimited..

Code:

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

#define SERVER_TCP_PORT                7000        // Default port
#define BUFLEN                        1024          // Buffer length

int sent = 0;
int acked = 0;

int main (int argc, char **argv)
{
 
  int n,bytes_to_read, maxmessages, sd, port;
  char  *host, *bp, rbuf[BUFLEN], **pptr, sbuf[BUFLEN];
  struct hostent *hp;
  struct sockaddr_in server;
  char str[16];
  pid_t getpid(void);
  n=0;
 
 
 
  switch(argc)
  {
    case 2:
      host =        argv[1];        // Host name
      port =        SERVER_TCP_PORT;
      maxmessages = 0;
      break;
    case 3:
      host =        argv[1];
      port =        SERVER_TCP_PORT;        // User specified port
      maxmessages = atoi(argv[2]);
      break;
    case 4:
      host =        argv[1];
      port =        SERVER_TCP_PORT;        // User specified port
      maxmessages = atoi(argv[2]);
      memcpy(sbuf,argv[3],BUFLEN);
      break;
     
    default:
      fprintf(stderr, "Usage: %s host # of message\n", argv[0]);
      exit(1);
  }
 
  // Create the socket
  if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  {
    perror("Cannot create socket");
    exit(1);
  }
  bzero((char *)&server, sizeof(struct sockaddr_in));
  server.sin_family = AF_INET;
  server.sin_port = htons(port);
  if ((hp = gethostbyname(host)) == NULL)
  {
    fprintf(stderr, "Unknown server address\n");
    exit(1);
  }
  bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length);
 
  // Connecting to the server
  if (connect (sd, (struct sockaddr *)&server, sizeof(server)) == -1)
  {
    fprintf(stderr, "Can't connect to server\n");
    perror("connect");
    exit(1);
  }
  printf("Connected:\nServer Name: %s\n", hp->h_name);
  pptr = hp->h_addr_list;
  printf("\t\tIP Address: %s\n", inet_ntop(hp->h_addrtype, *pptr, str, sizeof(str)));
 
  if (argv[3] == NULL) {
    printf("ENTER DATA TO BE SENT\n");
    fgets (sbuf, BUFLEN, stdin);
  }
 
  while(1){
   
    if ( maxmessages == 0 ) {
      for(;;) {
        FILE *fp;
        // Transmit data through the socket
        printf("\nTransmiting %u:\n", sent);
        send(sd, sbuf, BUFLEN, 0);
       
        /* Time start stuff */
        char buffer[30];
        struct timeval tv;
        time_t curtime;
       
        /* File I/O Preparations */
        fp=fopen("client-output.txt", "a"); /* Open file */
       
        /* Start time */
        gettimeofday(&tv, NULL);
        curtime=tv.tv_sec;
        strftime(buffer,30,"%m-%d-%Y  %T.",localtime(&curtime));
       
        fprintf(fp, "%u,Sent,%u,%ld\n",getpid(),sent,tv.tv_usec); /* Print start time */
       
        sent++;
       
        printf("Receiving %u:", acked);
        bp = rbuf;
        bytes_to_read = strlen("DATA-ACK");
       
        // client makes repeated calls to recv until no more data is expected to arrive.
        bp += n;
        bytes_to_read -= n;
       
        if (bytes_to_read <= 0)
        {
          printf("ACK\n");
          memset(rbuf,0,sizeof(rbuf));
        }
        /* Start time */
        gettimeofday(&tv, NULL);
        curtime=tv.tv_sec;
        strftime(buffer,30,"%m-%d-%Y  %T.",localtime(&curtime));
       
        fprintf(fp, "%u,Recv,%u,%ld\n",getpid(),acked,tv.tv_usec); /* Print start time */
        fclose(fp);
        acked++;
        sleep(10);       
      }
    }
    else {
     
      while(sent <= maxmessages) {
        FILE *fp;
        // Transmit data through the socket
        printf("Transmiting %u:\n", sent);
        send(sd, sbuf, BUFLEN, 0);
       
        /* Time start stuff */
        char buffer[30];
        struct timeval tv;
        time_t curtime;
       
        /* File I/O Preparations */
        fp=fopen("client-output.txt", "a"); /* Open file */
       
        /* Start time */
        gettimeofday(&tv, NULL);
        curtime=tv.tv_sec;
        strftime(buffer,30,"%m-%d-%Y  %T.",localtime(&curtime));
       
        fprintf(fp, "%u,Sent,%u,%ld,\n",getpid(),sent,tv.tv_usec); /* Print start time */
       
        sent++;
       
        printf("Receiving %u:", acked);
        bp = rbuf;
        bytes_to_read = strlen("DATA-ACK");
       
        // client makes repeated calls to recv until no more data is expected to arrive.
        bp += n;
        bytes_to_read -= n;
       
        if (bytes_to_read <= 0)
        {
          printf("ACK\n");
          memset(rbuf,0,sizeof(rbuf));
        }
        /* Start time */
        gettimeofday(&tv, NULL);
        curtime=tv.tv_sec;
        strftime(buffer,30,"%m-%d-%Y  %T.",localtime(&curtime));
       
        fprintf(fp, "%u,Recv,%u,%ld,\n",getpid(),acked,tv.tv_usec); /* Print start time */
        fclose(fp);
        acked++;
        sleep(10);       
      }
      fflush(stdout);
      close (sd);
      return (0);
     
    }
   
  }
  fflush(stdout);
  close (sd);
  return (0);
}


dwhitney67 02-17-2011 08:21 PM

Quote:

Originally Posted by Lantzvillian (Post 4262047)
... but I am still being blocked I think.

Yes, because of this:
Code:

  while(1) {
You have nothing in your code to exit the while-loop, other than when the write() fails. The write would fail if the client closes their socket.

Anyhow, while you are in the while-loop, you never return to the main() function to service other connections. Maybe that's what you want, but I got the impression from your first post that you wanted to be able to service multiple clients.

Go back to your code, try to remove the excessive error checking. It is nauseating to read code where 67% of it is merely diagnostic code to print error messages. Perhaps you should also avoid using non-blocking sockets; you did not heed much attention to what I stated earlier (ie. Item 2).


P.S. bcopy() and bzero() were deprecated a decade ago. Use memcpy() and memset() instead.

P.S. #2 Where is your client code calling recv()?

Lantzvillian 02-19-2011 03:22 PM

Great.. getting rid of the while(1) allowed another client to connect :)

The client doesn't need a recv since it uses read no?

However, now when the server prints out the message it sees from the client, it is doing this:

Code:

Initializing remote address: 127.0.0.1
Connections to date: 1
127.0.0.1,Recv,message1
127.0.0.1,Recv,;message1
127.0.0.1,Recv,1;message1
127.0.0.1,Recv,01;message1
127.0.0.1,Recv,=01;message1
epoll: EPOLLERR - Disconnect

I'm guessing its something to do with the length of the buffer and how much to read.

EDIT:// fixed! error was in bytes_to_read = BUFLEN -1; removed the -1 and off to the races.

Soo I have one connection from a client sending traffic and recieving a DATA-ACK. And then a second client connects.. DATA-ACKS stop being sent back to the client.. what should I do to rememdy this? I am thinking that epoll isn't rotating through the sockets?

Latest server code.
Code:

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#include <strings.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>

#define TRUE                1
#define FALSE                0
#define EPOLL_QUEUE_LEN 256
#define BUFLEN                1024
#define SERVER_PORT        7000

//Globals
int fd_server;

struct clientStuff
{
  int sockfd;
  struct sockaddr_in client;
};

// Function prototypes
static void SystemFatal (const char* message);
static int ClearSocket (void* arg);
void close_fd (int);

int main (int argc, char* argv[])

  int i, arg, visits,num_fds, fd_new, epoll_fd;
  static struct epoll_event events[EPOLL_QUEUE_LEN], event;
  int port = SERVER_PORT;
  struct sockaddr_in addr, remote_addr;
  socklen_t addr_size = sizeof(struct sockaddr_in);
  struct sigaction act;
  FILE *fp;
  visits =  0;
 
  // set up the signal handler to close the server socket when CTRL-c is received
  act.sa_handler = close_fd;
  act.sa_flags = 0;
  if ((sigemptyset (&act.sa_mask) == -1 || sigaction (SIGINT, &act, NULL) == -1))
  {
    perror ("Failed to set SIGINT handler");
    exit (EXIT_FAILURE);
  }
 
  // Create the listening socket
  fd_server = socket (AF_INET, SOCK_STREAM, 0);
  if (fd_server == -1)  {
    SystemFatal("socket");
  }
 
  // set SO_REUSEADDR so port can be resused imemediately after exit, i.e., after CTRL-c
  arg = 1;
  if (setsockopt (fd_server, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) == -1)  {
    SystemFatal("setsockopt");
  }
 
  // Make the server listening socket non-blocking
  if (fcntl (fd_server, F_SETFL, O_NONBLOCK | fcntl (fd_server, F_GETFL, 0)) == -1) {
    SystemFatal("fcntl");
  }
 
  // Bind to the specified listening port
  memset (&addr, 0, sizeof (struct sockaddr_in));
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = htonl(INADDR_ANY);
  addr.sin_port = htons(port);
 
  if (bind (fd_server, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
    SystemFatal("bind");
  }
 
  // Listen for fd_news; SOMAXCONN is 128 by default
  if (listen (fd_server, SOMAXCONN) == -1) {
    SystemFatal("listen");
  }
 
  // Create the epoll file descriptor
  epoll_fd = epoll_create(EPOLL_QUEUE_LEN);
 
  if (epoll_fd == -1) {
    SystemFatal("epoll_create");
  }
 
  // Add the server socket to the epoll event loop
  event.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLET;
  event.data.fd = fd_server;
  if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, fd_server, &event) == -1) {
    SystemFatal("epoll_ctl");
  }
 
  // Execute the epoll event loop
  while (TRUE)
  {
    num_fds = epoll_wait (epoll_fd, events, EPOLL_QUEUE_LEN, -1);
    if (num_fds < 0) {
      SystemFatal ("Error in epoll_wait!");
    }
   
    for (i = 0; i < num_fds; i++)
    {
      struct clientStuff c1;
     
      // Case 1: Error condition
      if (events[i].events & (EPOLLHUP | EPOLLERR))
      {
        fputs("epoll: EPOLLERR - Disconnect\n", stderr);
        close(events[i].data.fd);
        continue;
      }
      assert (events[i].events & EPOLLIN);
     
      // Case 2: Server is receiving a connection request
      if (events[i].data.fd == fd_server)
      {
        fd_new = accept (fd_server, (struct sockaddr*) &remote_addr, &addr_size);
        printf(">> Initializing remote address: %s\n", inet_ntoa(remote_addr.sin_addr));       
        visits++;
        c1.sockfd = fd_new;
        c1.client = remote_addr;
       
        fp=fopen("server-output.txt", "a"); /* Open file */
        fprintf(fp,"Connections-to-date,%u\n",visits);
        fprintf(fp,"%s,connect\n",inet_ntoa(remote_addr.sin_addr));
        fclose(fp);
       
        printf("Connections to date: %u \n",visits);         
       
        if (fd_new == -1)
        {
          if (errno != EAGAIN && errno != EWOULDBLOCK)
          {
            perror("accept");
          }
          continue;
        }
       
        // Make the fd_new non-blocking
        if (fcntl (fd_new, F_SETFL, O_NONBLOCK | fcntl(fd_new, F_GETFL, 0)) == -1)
          SystemFatal("fcntl");
       
        // Add the new socket descriptor to the epoll loop
          event.data.fd = fd_new;
          if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, fd_new, &event) == -1){
            SystemFatal ("epoll_ctl");
          }
          continue;
      }
     
      // Case 3: One of the sockets has read data
      ClearSocket(&c1);
    }
  }
  close(fd_server);
  exit (EXIT_SUCCESS);
}


/*
* Function that contains the work for every client
*/
static int ClearSocket (void* arg)
{
  struct clientStuff *ptr;
  struct sockaddr_in client_addr;
  int bytes_to_read, sockfd;
  char *bp, buf[BUFLEN];
  ssize_t n;
  FILE *fp;
 
  ptr = (struct clientStuff *)arg;
  sockfd = ptr->sockfd;
  client_addr = ptr->client;
  bp = buf;
  bytes_to_read = BUFLEN;
 
  n = read(sockfd, bp, bytes_to_read);
 
  bp += n;
  bytes_to_read -= n;
 
  if (bytes_to_read <= 0)
  {
    fp=fopen("server-output.txt", "a");
    fprintf(fp,"%s,Recv,%s\n",inet_ntoa(client_addr.sin_addr), buf);
    fclose(fp);
    printf("%s,Recv,%s\n", inet_ntoa(client_addr.sin_addr), buf);
   
    if((write(sockfd, "DATA-ACK", strlen("DATA-ACK"))) == -1) {
    //close(sockfd);
    return 0;
  }
  }
 
 // sleep(9);
 
  return 1;
}

/*
* Prints the error stored in errno and aborts the program.
*/
static void SystemFatal(const char* message)
{
  perror (message);
  exit (EXIT_FAILURE);
}

/*
* close fd
*/
void close_fd (int signo)
{
  close(fd_server);
  exit (EXIT_SUCCESS);
}


dwhitney67 02-19-2011 08:59 PM

I wrote an app that, to the best of my knowledge, works. Maybe you could steal an idea or two?


Code:

#include <sys/types.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>

#define MAX(a,b)  ((a) > (b) ? (a) : (b))


int fillAddress(int domain, const char* address, const unsigned short port, struct sockaddr_in* sin);


int main(int argc, char** argv)
{
  int tcpListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

  // bind sockets to port using respective domain
  struct sockaddr_in tcp_sin;

  assert(fillAddress(AF_INET, NULL, 9000, &tcp_sin) == 0);

  assert(bind(tcpListen, (struct sockaddr*) &tcp_sin, sizeof(struct sockaddr_in)) == 0);

  // listen on tcp socket
  assert(listen(tcpListen, 5) == 0);

  int epoll_fd = epoll_create(10);

  // Add the server socket to the epoll event loop
  struct epoll_event event;

  event.events  = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLET;
  event.data.fd = tcpListen;

  assert(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, tcpListen, &event) == 0);

  for (;;)
  {
      struct epoll_event events[10];

      memset(&events, 0, sizeof(events));

      int num_fds = epoll_wait(epoll_fd, events, 10, -1);

      for (int i = 0; i < num_fds; ++i)
      {
        if (events[i].events & (EPOLLHUP | EPOLLERR))
        {
            close(events[i].data.fd);
        }
        else if (events[i].events & EPOLLIN)
        {
            if (events[i].data.fd == tcpListen)
            {
              printf("client connected!\n");

              int client = accept(tcpListen, NULL, NULL);

              event.events  = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLET;
              event.data.fd = client;

              assert(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client, &event) == 0);
            }
            else
            {
              printf("detected activity from a client w/ sd = %d.\n", events[i].data.fd);

              char buf[1024];

              int bytes = recv(events[i].data.fd, buf, sizeof(buf) - 1, 0);

              if (bytes > 0)
              {
                  buf[bytes] = '\0';
                  printf("%s\n", buf);
              }
              else if (bytes == 0)
              {
                  printf("client disconnected\n");
                  assert(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL) == 0);
              }
            }
        }
      }
  }

  return 0;
}


int fillAddress(int domain, const char* address, const unsigned short port, struct sockaddr_in* sin)
{
  if (!address || strlen(address) == 0)
  {
    memset(sin, 0, sizeof(struct sockaddr_in));

    sin->sin_family      = domain;
    sin->sin_addr.s_addr = htonl(INADDR_ANY);
    sin->sin_port        = htons(port);
  }
  else
  {
    struct addrinfo  hints;
    struct addrinfo* host_info = 0;

    memset(&hints, 0, sizeof(hints));

    hints.ai_family = domain;

    char portstr[6] = {0};
    snprintf(portstr, sizeof(portstr), "%d", port);

    if (getaddrinfo(address, portstr, &hints, &host_info) != 0  ||
        !host_info || !host_info->ai_addr || host_info->ai_family != domain)
    {
      if (host_info) freeaddrinfo(host_info);
      return -1;
    }

    memcpy(sin, host_info->ai_addr, sizeof(struct sockaddr_in));
    sin->sin_port = htons(port);

    freeaddrinfo(host_info);
  }

  return 0;
}



All times are GMT -5. The time now is 07:43 AM.