Multithreaded HTTP Server for Linux

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

 



        Multithreaded HTTP Server for Linux built up by the pool of threads
                           utilizing select() system call.

Developing code bellow we follow general guidelines from [1] chapter 11.
The only one source file has been modified is server.c.
Instead of fork new process to handle each incoming client's connection,
as procedure server_run ( ) does in [1], we start pool of 1024 threads
accepting as parameter descriptor of passive socket.
The procedure run by each thread is asynchronous BSD socket?s server utilizing
select() system call (see for example [2],chapter 13(5)) to switch between handling
incoming client's requests by accept() system call and receiving "http" requests
from clients already connected to server utilizing procedures
handle_request() and handle_get() from [1],chapter 11.


References

1.Mark Mitchel,Jeffrey Oldham,Alex Samuel. Advanced Linux Programming.
New Riders Publishing , 2001. www.advancedlinuxprogramming.com

2.Douglas E. Comer,David L. Stevens Internet Working with TCP/IP ,vol 3
Client-Server Programming and application Linux/Posix Socket Version,
Prentice Hall,Inc. 2001

/*
*   server.c  module :- multithreaded version, starting pool of threads,
*   multiplexing select() system call, to serve new connections
*   utilizing accept() system call and "http" responds for clients
*   already connected to server simultaneously.
*/

#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pthread.h>
#include "server.h"
#define NUM_THREADS 1024

pthread_mutex_t get_mutex=PTHREAD_MUTEX_INITIALIZER;

static char* not_found_response_template =
 "HTTP/1.0 404 Not Found\n"
 "Content-type: text/html\n"
 "\n"
 "<html>\n"
 " <body>\n"
 "  <h1>Not Found</h1>\n"
 "  <p>The requested URL %s was not found on this server.</p>\n"
 " </body>\n"
 "</html>\n";


static char* bad_method_response_template = "HTTP/1.0 501 Method Not Implemented\n" "Content-type: text/html\n" "\n" "<html>\n" " <body>\n" " <h1>Method Not Implemented</h1>\n" " <p>The method %s is not implemented by this server.</p>\n" " </body>\n" "</html>\n"; static char* ok_response = "HTTP/1.0 200 OK\n" "Content-type: text/html\n" "\n";

static char* bad_request_response =
 "HTTP/1.0 400 Bad Request\n"
 "Content-type: text/html\n"
 "\n"
 "<html>\n"
 " <body>\n"
 "  <h1>Bad Request</h1>\n"
 "  <p>This server did not understand your request.</p>\n"
 " </body>\n"
 "</html>\n";

void
die(const char *func, int err)
{
       fprintf(stderr,"%s: %s\n",func,strerror(err));
       abort();
}

static void handle_get (int connection_fd, const char* page)
{
 struct server_module* module = NULL;
 if (*page == '/' && strchr (page + 1, '/') == NULL) {
   char module_file_name[64];
   snprintf (module_file_name, sizeof (module_file_name),
             "%s.so", page + 1);
   module = module_open (module_file_name);
 }

if (module == NULL) {
char response[1024];
snprintf (response, sizeof (response), not_found_response_template, page);
write (connection_fd, response, strlen (response));
}
else {
write (connection_fd, ok_response, strlen (ok_response));
(*module->generate_function) (connection_fd);
module_close (module);
}
}
static void *
handle_connection (int fdSock)
{
int connection_fd = fdSock;
char buffer[256];
ssize_t bytes_read;
bytes_read = read (connection_fd, buffer, sizeof (buffer) - 1);
if (bytes_read > 0) {
char method[sizeof (buffer)];
char url[sizeof (buffer)];
char protocol[sizeof (buffer)];


   buffer[bytes_read] = '\0';
   sscanf (buffer, "%s %s %s", method, url, protocol);
   while (strstr (buffer, "\r\n\r\n") == NULL)
     bytes_read = read (connection_fd, buffer, sizeof (buffer));
   if (bytes_read == -1) {
     close (connection_fd);
     return;
   }
   if (strcmp (protocol, "HTTP/1.0") && strcmp (protocol, "HTTP/1.1")) {
     write (connection_fd, bad_request_response,
            sizeof (bad_request_response));
   }
   else if (strcmp (method, "GET")) {
     char response[1024];
     snprintf (response, sizeof (response),
               bad_method_response_template, method);
     write (connection_fd, response, strlen (response));
   }
   else
      handle_get (connection_fd, url);
 }
 else if (bytes_read == 0)
     ;
 else {
   system_error ("read");
  }
close(connection_fd);
}

void *
serv_request(void *insock)
{
int msock = (int)insock;
struct sockaddr_in fsin;
fd_set rfds;
fd_set afds;
unsigned int alen;
int fd,nfds;
int rval;
socklen_t address_length;
struct sockaddr_in socket_address;

nfds=getdtablesize();

FD_ZERO(&afds);
FD_SET(msock,&afds);

while(1) {
memcpy(&rfds,&afds,sizeof(rfds));
if (select(nfds,&rfds,(fd_set *)0,(fd_set *)0,(struct timeval *)0) < 0)
         die("select()",errno);
if (FD_ISSET(msock,&rfds)) {
 int ssock;
 alen=sizeof(fsin);
 /*
  Serving new incoming client's connection
 */
 pthread_mutex_lock(&get_mutex);
   ssock=accept(msock,(struct sockaddr *)&fsin,&alen);
 pthread_mutex_unlock(&get_mutex);
 if (ssock < 0)
   die ("accept()",errno);
 if (verbose) {
     socklen_t address_length;

     address_length = sizeof (socket_address);
     rval = getpeername (ssock, &socket_address, &address_length);
     assert (rval == 0);
     printf ("Thread '%d' accepted connection from %s\n",
             pthread_self(),inet_ntoa (socket_address.sin_addr));
   }
 FD_SET(ssock,&afds);
}
for (fd=0;fd < nfds; ++fd)
if (fd != msock && FD_ISSET(fd,&rfds)) {
 printf("Thread '%d' responding request...\n",pthread_self());
 /*
  Serving client had been already connected to server
 */
 handle_connection(fd);
 FD_CLR(fd,&afds);
 }
}
}


void server_run(struct in_addr local_address,uint16_t port) { struct sockaddr_in socket_address; int rval; int server_socket; int k; /* Getting socket's descriptor to be passed to each thread in the pool */ server_socket = socket (PF_INET, SOCK_STREAM, 0); if (server_socket == -1) system_error ("socket"); memset (&socket_address, 0, sizeof (socket_address)); socket_address.sin_family = AF_INET; socket_address.sin_port = port; socket_address.sin_addr = local_address; rval = bind (server_socket, &socket_address, sizeof (socket_address)); if (rval != 0) system_error ("bind"); rval = listen (server_socket, 10); if (rval != 0) system_error ("listen"); if (verbose) { socklen_t address_length; address_length = sizeof (socket_address); rval = getsockname (server_socket, &socket_address, &address_length); assert (rval == 0); printf ("server listening on %s:%d\n", inet_ntoa (socket_address.sin_addr), (int) ntohs (socket_address.sin_port)); }

/*
Starting pool of threads building up HTTP server
*/

size_t stacksize;
pthread_t p_thread[NUM_THREADS];
pthread_attr_t attr;
  pthread_attr_init(&attr);
  stacksize = 500000;
  pthread_attr_setstacksize (&attr, stacksize);
  pthread_attr_getstacksize (&attr, &stacksize);

for(k=0; k<NUM_THREADS; k++) {
     pthread_create(&p_thread[k],&attr,serv_request,(void*)server_socket);
}

pthread_attr_destroy(&attr);

for(k=0;k<NUM_THREADS;k++) {
       pthread_join(p_thread[k], NULL);
       printf("Completed join with thread %d\n",k);
     }
}

_________________________________________________________________
FREE pop-up blocking with the new MSN Toolbar ? get it now! http://toolbar.msn.click-url.com/go/onm00200415ave/direct/01/



-- redhat-list mailing list unsubscribe mailto:redhat-list-request@xxxxxxxxxx?subject=unsubscribe https://www.redhat.com/mailman/listinfo/redhat-list

[Index of Archives]     [CentOS]     [Kernel Development]     [PAM]     [Fedora Users]     [Red Hat Development]     [Big List of Linux Books]     [Linux Admin]     [Gimp]     [Asterisk PBX]     [Yosemite News]     [Red Hat Crash Utility]


  Powered by Linux