LinuxQuestions.org
Help answer threads with 0 replies.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 02-16-2011, 03:05 PM   #1
Lantzvillian
Member
 
Registered: Oct 2007
Location: BC, Canada
Distribution: Fedora, Debian
Posts: 210

Rep: Reputation: 41
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);
}

Last edited by Lantzvillian; 02-16-2011 at 03:20 PM.
 
Old 02-17-2011, 01:10 PM   #2
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,522

Rep: Reputation: 332Reputation: 332Reputation: 332Reputation: 332
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.
 
Old 02-17-2011, 04:09 PM   #3
Lantzvillian
Member
 
Registered: Oct 2007
Location: BC, Canada
Distribution: Fedora, Debian
Posts: 210

Original Poster
Rep: Reputation: 41
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);
}

Last edited by Lantzvillian; 02-17-2011 at 05:32 PM.
 
Old 02-17-2011, 08:21 PM   #4
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,522

Rep: Reputation: 332Reputation: 332Reputation: 332Reputation: 332
Quote:
Originally Posted by Lantzvillian View Post
... 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()?

Last edited by dwhitney67; 02-17-2011 at 08:27 PM.
 
Old 02-19-2011, 03:22 PM   #5
Lantzvillian
Member
 
Registered: Oct 2007
Location: BC, Canada
Distribution: Fedora, Debian
Posts: 210

Original Poster
Rep: Reputation: 41
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);
}

Last edited by Lantzvillian; 02-19-2011 at 03:58 PM.
 
Old 02-19-2011, 08:59 PM   #6
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,522

Rep: Reputation: 332Reputation: 332Reputation: 332Reputation: 332
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;
}
 
1 members found this post helpful.
  


Reply

Tags
sockets, [c]


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Clumsy interface of epoll saurabhth Programming 1 05-27-2009 03:50 PM
epoll jopu Linux - Networking 0 11-05-2007 11:27 PM
How to create concurrent Server rajprabhu2k Programming 6 08-21-2007 08:12 AM
epoll missing on slackware 11.0?? flatline- Slackware 3 12-10-2006 02:02 PM
epoll problem Parahat Melayev Programming 1 03-17-2005 05:22 AM


All times are GMT -5. The time now is 09:26 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration