Epoll-based HTTP server (added to thread pool)
(19:02:51)
Reprinted token
Tags:
Miscellaneous
Category: epoll
# Include <fcntl. h>
# Include <cstdio>
# Include <unistd. h>
# Include <cstdlib>
# Include <sys/socket. h>
# Include <sys/epoll. h>
# Include <netinet/in. h>
# Include <ARPA/inet. h>
# Include <errno. h>
# Include <cstring>
# Include <pthread. h>
Const int epoll_size = 5000;
Const int event_arr = 5000;
Const int Port = 8002;
Const int buf_size = 5000;
Const int back_queue = 100;
Const int thread_max= 100;
Static unsigned int s_thread_para [thread_max] [8]; // thread parameters
Static pthread_t s_tid [thread_max]; // thread ID
Pthread_mutex_t s_mutex [thread_max]; // thread lock
Int epfd; // epoll
Struct epoll_event eV, Evs [event_arr];
Char * get_type (char * URL, char * BUF)
{
Const char * t = URL + strlen (URL );
Char type [64];
For (; t> = URL & * t! = '.'; -- T );
Strcpy (type, t + 1 );
If (strcmp (type, "html") = 0 | strcmp (type, "htm") = 0)
Sprintf (BUF, "text/% s", type );
Else if (strcmp (type, "GIF") = 0 |
Strcmp (type, "jpg") = 0 |
Strcmp (type, "Jpeg") = 0 |
Strcmp (type, "PNG") = 0)
Sprintf (BUF, "image/% s", type );
Else if (strcmp (type, "/") = 0)
Sprintf (BUF, "text/html ");
Else if (strcmp (type, "CSS") = 0)
Sprintf (BUF, "text/CSS ");
Else if (strcmp (type, "JS") = 0)
Sprintf (BUF, "application/X-JavaScript ");
Else
{
Sprintf (BUF, "unknown ");
}
Return Buf;
}
Void * http_server (INT thread_para [])
{
Int pool_index; // thread pool ID
Int clientfd; // client socket
Char Buf [buf_size];
Pthread_detach (pthread_self ());
Pool_index = thread_para [7];
Wait_unlock:
Pthread_mutex_lock (s_mutex + pool_index); // wait for thread unlock
Clientfd = thread_para [1]; // client socket ID
// Tentatively read data first
Int Len = read (clientfd, Buf, buf_size );
Printf ("% s", Buf );
If (LEN> 0)
{
Char * token = strtok (BUF, ""); // get
Printf ("token: % s", token );
Char type [64];
Char * url = strtok (null, ""); // URL
While (* url = '.' | * url = '/') + + URL;
Printf ("url: % s", URL );
Char file [1280000];
Sprintf (file, "% s", URL );
Printf ("file: % s", file );
File * fp = fopen (file, "rb ");
If (FP = 0)
{
Char response [] = "HTTP/1.1 404 Not found \ r \ n ";
Printf ("HTTP/1.1 404 Not found \ r \ n ");
Write (clientfd, response, strlen (response ));
}
Else
{
Int file_size;
Char * content;
Char * response;
Fseek (FP, 0, seek_end );
File_size = ftell (FP );
Fseek (FP, 0, seek_set );
Content = (char *) malloc (file_size + 1 );
Response = (char *) malloc (200 );
Fread (content, file_size, 1, FP );
Content [file_size] = 0;
Sprintf (response, "HTTP/1.1 200 OK \ r \ ncontent-length: % d \ r \ ncontent-type: % s \ r \ n", file_size, get_type (URL, type ));
// Printf ("HTTP/1.1 200 OK \ r \ ncontent-type: % s \ r \ ncontent-length: % d \ r \ n % s ", get_type (URL, type), file_size, content );
Write (clientfd, response, strlen (response ));
Write (clientfd, content, file_size );
Free (content );
Free (response );
}
}
Else if (LEN = 0)
{
// The epoll event is triggered but not read, which indicates disconnection.
// Printf ("client closed at % s \ n", inet_ntoa (clientaddr. sin_addr ));
Epoll_ctl (epfd, epoll_ctl_del, clientfd, & eV );
Close (clientfd );
Int I = thread_para [3];
EVS [I]. Data. FD =-1;
}
Else if (LEN = eagain)
{
Printf ("socket Huan Cun man le! \ N ");
}
Else
{
// An error occurred while reading the client.
Printf ("client read failed! \ N ");
}
Thread_para [0] = 0; // sets the thread occupation flag to "idle"
Goto wait_unlock;
Printf ("pthread exit! \ N ");
Pthread_exit (null );
}
Static int init_thread_pool (void)
{
Int I, RC;
For (I = 0; I <thread_max; I ++)
{
S_thread_para [I] [0] = 0; // idle
S_thread_para [I] [7] = I; // thread pool ID
Pthread_mutex_lock (s_mutex + I); // thread lock
}
// Create Thread Pool
For (I = 0; I <thread_max; I ++)
{Rc = pthread_create (s_tid + I, 0, (void * (*) (void *) & http_server, (void *) (s_thread_para [I]);
If (0! = RC)
{Fprintf (stderr, "Create thread failed! \ N ");
Return-1;
}
}
Return 0;
}
Void setnoblock (INT sockfd) // sets the non-blocking mode.
{
Int OPT;
If (OPT = fcntl (sockfd, f_getfl) <0) // obtain the original flag;
{
Printf ("get fl failed! \ N ");
Exit (-1 );
}
Opt | = o_nonblock;
If (fcntl (sockfd, f_setfl, OPT) <0)
Printf ("set FL failed! \ N ");
}
Int main ()
{
Int serverfd, J;
Serverfd = socket (af_inet, sock_stream, 0); // create a server FD
Setnoblock (serverfd); // set to non-blocking mode
Unsigned int optval;
Struct linger optval1;
// Set the so_reuseaddr option (fast server restart)
Optval = 0x1;
Setsockopt (serverfd, sol_socket, so_reuseaddr, & optval, 4 );
// Set the so_linger option (prevent close_wait from hanging all sockets)
Optval1.l _ Onoff = 1;
Optval1.l _ linger = 60;
Setsockopt (serverfd, sol_socket, so_linger, & optval1, sizeof (struct linger ));
// Create an epoll and put serverfd In the listener queue
Epfd = epoll_create (epoll_size );
Ev. Data. FD = serverfd;
Ev. Events = epollin | epollet;
Epoll_ctl (epfd, epoll_ctl_add, serverfd, & eV );
// Bind the server port
Struct sockaddr_in serveraddr;
Socklen_t serverlen = sizeof (struct sockaddr_in );
Serveraddr. sin_addr.s_addr = htonl (inaddr_any );
Serveraddr. sin_port = htons (port );
If (BIND (serverfd, (struct sockaddr *) & serveraddr, serverlen ))
{
Printf ("bind failed! \ N ");
Exit (-1 );
}
// Thread pool Initialization
Int rc = init_thread_pool ();
If (0! = RC) Exit (-1 );
// Enable the listener
If (Listen (serverfd, back_queue ))
{
Printf ("Listen failed! \ N ");
Exit (-1 );
}
// Service Processing
Int clientfd;
Sockaddr_in clientaddr;
Socklen_t clientlen;
For (;;)
{
// Wait for the epoll event to arrive. A maximum of event_arr events can be retrieved.
Int NFDs = epoll_wait (epfd, EVS, event_arr,-1 );
// Process the event
For (INT I = 0; I <NFDs; I ++)
{
If (EVS [I]. Data. FD = serverfd & EVS [I]. Events & epollin)
{
// If serverfd is used, a new connection is established.
If (clientfd = accept (serverfd, (struct sockaddr *) & clientaddr, & clientlen) <0)
{
Printf ("Accept failed \ n ");
}
Printf ("connect from % s: % d \ n", inet_ntoa (clientaddr. sin_addr), htons (clientaddr. sin_port ));
Setnoblock (clientfd );
// Register the connection from accept ()
Ev. Data. FD = clientfd;
Ev. Events = epollin | epollet;
Epoll_ctl (epfd, epoll_ctl_add, clientfd, & eV );
}
Else if (EVS [I]. Events & epollin)
{
// If it is not serverfd, the client is readable.
Printf ("client can write! \ N ");
If (clientfd = EVS [I]. Data. FD)> 0)
{
// Query the idle Thread Pair
For (j = 0; j <thread_max; j ++ ){
If (0 = s_thread_para [J] [0]) break;
}
If (j> = thread_max ){
Fprintf (stderr, "the thread pool is full and the connection will be dropped \ r \ n ");
Shutdown (clientfd, shut_rdwr );
Close (clientfd );
Continue;
}
// Copy related parameters
S_thread_para [J] [0] = 1; // set the activity flag to "activity"
S_thread_para [J] [1] = clientfd; // Client Connection
S_thread_para [J] [2] = serverfd; // service index
S_thread_para [J] [3] = I; // epoll event ID;
// Unlock the thread
Pthread_mutex_unlock (s_mutex + J );}
Else printf ("other error! \ N ");
}
}
}
Return 0;
}