Multithreaded HTTP Server for Linux built up by the pool of threads multiplexing 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); } }
_________________________________________________________________
MSN Toolbar provides one-click access to Hotmail from any Web page ? FREE download! http://toolbar.msn.click-url.com/go/onm00200413ave/direct/01/
_______________________________________________ Redhat-devel-list mailing list Redhat-devel-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/redhat-devel-list