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;
}