This Multi-threaded web server takes advantage of the posix thread library to enable it it serve multiple files at the same time. Compile using gcc and run on a linux server.
// Multi-Threaded web server using posix pthreads // BK Turley 2011 //this simple web server is capible of serving simple html, jpg, gif & text files //----- Include files --------------------------------------------------------- #include <stdio.h> // for printf() #include <stdlib.h> // for exit() #include <string.h> // for strcpy(),strerror() and strlen() #include <fcntl.h> // for file i/o constants #include <sys/stat.h> // for file i/o constants #include <errno.h> /* FOR BSD UNIX/LINUX ---------------------------------------------------- */ #include <sys/types.h> // #include <netinet/in.h> // #include <sys/socket.h> // for socket system calls #include <arpa/inet.h> // for socket system calls (bind) #include <sched.h> #include <pthread.h> /* P-thread implementation */ #include <signal.h> /* for signal */ #include <semaphore.h> /* for p-thread semaphores */ /* ------------------------------------------------------------------------ */ //----- HTTP response messages ---------------------------------------------- #define OK_IMAGE "HTTP/1.0 200 OKnContent-Type:image/gifnn" #define OK_TEXT "HTTP/1.0 200 OKnContent-Type:text/htmlnn" #define NOTOK_404 "HTTP/1.0 404 Not FoundnContent-Type:text/htmlnn" #define MESS_404 "<html><body><h1>FILE NOT FOUND</h1></body></html>" //----- Defines ------------------------------------------------------------- #define BUF_SIZE 1024 // buffer size in bytes #define PORT_NUM 6110 // Port number for a Web server (TCP 5080) #define PEND_CONNECTIONS 100 // pending connections to hold #define TRUE 1 #define FALSE 0 #define NTHREADS 5 /* Number of child threads */ #define NUM_LOOPS 10 /* Number of local loops */ #define SCHED_INTVL 5 /* thread scheduling interval */ #define HIGHPRIORITY 10 /* global variables ---------------------------------------------------- */ sem_t thread_sem[NTHREADS]; int next_thread; int can_run; int i_stopped[NTHREADS]; unsigned int client_s; // Client socket descriptor /* Child thread implementation ----------------------------------------- */ void *my_thread(void * arg) { unsigned int myClient_s; //copy socket /* other local variables ------------------------------------------------ */ char in_buf[BUF_SIZE]; // Input buffer for GET resquest char out_buf[BUF_SIZE]; // Output buffer for HTML response char *file_name; // File name unsigned int fh; // File handle (file descriptor) unsigned int buf_len; // Buffer length for file reads unsigned int retcode; // Return code myClient_s = *(unsigned int *)arg; // copy the socket /* receive the first HTTP request (HTTP GET) ------- */ retcode = recv(client_s, in_buf, BUF_SIZE, 0); /* if receive error --- */ if (retcode < 0) { printf("recv error detected ...n"); } /* if HTTP command successfully received --- */ else { /* Parse out the filename from the GET request --- */ strtok(in_buf, " "); file_name = strtok(NULL, " "); //test for high priority file if(0 == strcmp(&file_name[1],"test_00.jpg")){ int diditwork = pthread_setschedprio(pthread_self(), HIGHPRIORITY); if(!diditwork) printf("priority wasn't increased correctly ...n"); else{ printf("High priority thread created ...n"); } } /* Open the requested file (start at 2nd char to get rid of leading "") */ fh = open(&file_name[1], O_RDONLY, S_IREAD | S_IWRITE); /* Generate and send the response (404 if could not open the file) */ if (fh == -1) { printf("File %s not found - sending an HTTP 404 n", &file_name[1]); strcpy(out_buf, NOTOK_404); send(client_s, out_buf, strlen(out_buf), 0); strcpy(out_buf, MESS_404); send(client_s, out_buf, strlen(out_buf), 0); } else { printf("File %s is being sent n", &file_name[1]); if ((strstr(file_name, ".jpg") != NULL)||(strstr(file_name, ".gif") != NULL)) { strcpy(out_buf, OK_IMAGE); } else { strcpy(out_buf, OK_TEXT); } send(client_s, out_buf, strlen(out_buf), 0); buf_len = 1; while (buf_len > 0) { buf_len = read(fh, out_buf, BUF_SIZE); if (buf_len > 0) { send(client_s, out_buf, buf_len, 0); //printf("%d bytes transferred ..n", buf_len); } } close(fh); // close the file close(client_s); // close the client connection pthread_exit(NULL); } } } //===== Main program ======================================================== int main(void) { /* local variables for socket connection -------------------------------- */ unsigned int server_s; // Server socket descriptor struct sockaddr_in server_addr; // Server Internet address //unsigned int client_s; // Client socket descriptor struct sockaddr_in client_addr; // Client Internet address struct in_addr client_ip_addr; // Client IP address int addr_len; // Internet address length unsigned int ids; // holds thread args pthread_attr_t attr; // pthread attributes pthread_t threads; // Thread ID (used by OS) /* create a new socket -------------------------------------------------- */ server_s = socket(AF_INET, SOCK_STREAM, 0); /* fill-in address information, and then bind it ------------------------ */ server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT_NUM); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); bind(server_s, (struct sockaddr *)&server_addr, sizeof(server_addr)); /* Listen for connections and then accept ------------------------------- */ listen(server_s, PEND_CONNECTIONS); /* the web server main loop ============================================= */ pthread_attr_init(&attr); while(TRUE) { printf("my server is ready ...n"); /* wait for the next client to arrive -------------- */ addr_len = sizeof(client_addr); client_s = accept(server_s, (struct sockaddr *)&client_addr, &addr_len); printf("a new client arrives ...n"); if (client_s == FALSE) { printf("ERROR - Unable to create socket n"); exit(FALSE); } else { /* Create a child thread --------------------------------------- */ ids = client_s; pthread_create ( /* Create a child thread */ &threads, /* Thread ID (system assigned) */ &attr, /* Default thread attributes */ my_thread, /* Thread routine */ ids); /* Arguments to be passed */ } } /* To make sure this "main" returns an integer --- */ close (server_s); // close the primary socket return (TRUE); // return code from "main" }