📄 http_server.cpp
字号:
// HTTP_Server.cpp,v 1.47 2006/01/16 17:08:19 spaunov Exp#ifndef ACE_BUILD_SVC_DLL#define ACE_BUILD_SVC_DLL#endif /* ACE_BUILD_SVC_DLL */#include "ace/OS_NS_string.h"#include "ace/Get_Opt.h"#include "ace/Asynch_Acceptor.h"#include "ace/LOCK_SOCK_Acceptor.h"#include "ace/Proactor.h"#include "ace/Signal.h"#include "ace/Auto_Ptr.h"#include "IO.h"#include "HTTP_Server.h"ACE_RCSID(server, HTTP_Server, "HTTP_Server.cpp,v 1.47 2006/01/16 17:08:19 spaunov Exp")// class is overkillclass JAWS{public: enum { JAWS_POOL = 0, JAWS_PER_REQUEST = 1 }; enum { JAWS_SYNCH = 0, JAWS_ASYNCH = 2 };};voidHTTP_Server::parse_args (int argc, ACE_TCHAR *argv[]){ int c; int thr_strategy = 0; int io_strategy = 0; const ACE_TCHAR *prog = argc > 0 ? argv[0] : ACE_TEXT ("HTTP_Server"); // Set some defaults this->port_ = 0; this->threads_ = 0; this->backlog_ = 0; this->throttle_ = 0; this->caching_ = true; ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("p:n:t:i:b:c:")); while ((c = get_opt ()) != -1) switch (c) { case 'p': this->port_ = ACE_OS::atoi (get_opt.opt_arg ()); break; case 'n': this->threads_ = ACE_OS::atoi (get_opt.opt_arg ()); break; case 't': // POOL -> thread pool // PER_REQUEST -> thread per request // THROTTLE -> thread per request with throttling if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("POOL")) == 0) thr_strategy = JAWS::JAWS_POOL; else if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("PER_REQUEST")) == 0) { thr_strategy = JAWS::JAWS_PER_REQUEST; this->throttle_ = 0; } else if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("THROTTLE")) == 0) { thr_strategy = JAWS::JAWS_PER_REQUEST; this->throttle_ = 1; } break; case 'f': if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("THR_BOUND")) == 0) { // What happened here? } else if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("THR_DAEMON")) == 0) { } else if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("THR_DETACHED")) == 0) { } case 'i': // SYNCH -> synchronous I/O // ASYNCH -> asynchronous I/O if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("SYNCH")) == 0) io_strategy = JAWS::JAWS_SYNCH; else if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("ASYNCH")) == 0) io_strategy = JAWS::JAWS_ASYNCH; break; case 'b': this->backlog_ = ACE_OS::atoi (get_opt.opt_arg ()); break; case 'c': if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("NO_CACHE")) == 0) this->caching_ = false; else this->caching_ = true; break; default: break; } // No magic numbers. if (this->port_ <= 0) this->port_ = 5432; if (this->threads_ <= 0) this->threads_ = 5; // Don't use number of threads as default if (this->backlog_ <= 0) this->backlog_ = this->threads_; this->strategy_ = thr_strategy | io_strategy; ACE_UNUSED_ARG (prog); ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("in HTTP_Server::init, %s port = %d, ") ACE_TEXT ("number of threads = %d\n"), prog, this->port_, this->threads_));}intHTTP_Server::init (int argc, ACE_TCHAR *argv[]) // Document this function{ // Ignore signals generated when a connection is broken unexpectedly. ACE_Sig_Action sig ((ACE_SignalHandler) SIG_IGN, SIGPIPE); ACE_UNUSED_ARG (sig); // Parse arguments which sets the initial state. this->parse_args (argc, argv); //If the IO strategy is synchronous (SYNCH case), then choose a handler //factory based on the desired caching scheme HTTP_Handler_Factory *f = 0; if (this->strategy_ != (JAWS::JAWS_POOL | JAWS::JAWS_ASYNCH)) if (this->caching_) ACE_NEW_RETURN (f, Synch_HTTP_Handler_Factory (), -1); else ACE_NEW_RETURN (f, No_Cache_Synch_HTTP_Handler_Factory (), -1); //NOTE: At this point f better not be a NULL pointer, //so please do not change the ACE_NEW_RETURN macros unless //you know what you are doing ACE_Auto_Ptr<HTTP_Handler_Factory> factory (f); // Choose what concurrency strategy to run. switch (this->strategy_) { case (JAWS::JAWS_POOL | JAWS::JAWS_ASYNCH) : return this->asynch_thread_pool (); case (JAWS::JAWS_PER_REQUEST | JAWS::JAWS_SYNCH) : return this->thread_per_request (*factory.get ()); case (JAWS::JAWS_POOL | JAWS::JAWS_SYNCH) : default: return this->synch_thread_pool (*factory.get ()); } ACE_NOTREACHED (return 0);}intHTTP_Server::fini (void){ this->tm_.close (); return 0;}intHTTP_Server::synch_thread_pool (HTTP_Handler_Factory &factory){ // Main thread opens the acceptor if (this->acceptor_.open (ACE_INET_Addr (this->port_), 1, PF_INET, this->backlog_) == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("HTTP_Acceptor::open")), -1); // Create a pool of threads to handle incoming connections. Synch_Thread_Pool_Task t (this->acceptor_, this->tm_, this->threads_, factory); this->tm_.wait (); return 0;}Synch_Thread_Pool_Task::Synch_Thread_Pool_Task (HTTP_Acceptor &acceptor, ACE_Thread_Manager &tm, int threads, HTTP_Handler_Factory &factory) : ACE_Task<ACE_NULL_SYNCH> (&tm), acceptor_ (acceptor), factory_ (factory){ if (this->activate (THR_DETACHED | THR_NEW_LWP, threads) == -1) ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("Synch_Thread_Pool_Task::open")));}intSynch_Thread_Pool_Task::svc (void){ // Creates a factory of HTTP_Handlers binding to synchronous I/O strategy //Synch_HTTP_Handler_Factory factory; for (;;) { ACE_SOCK_Stream stream; // Lock in this accept. When it returns, we have a connection. if (this->acceptor_.accept (stream) == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT ("HTTP_Acceptor::accept")), -1); ACE_Message_Block *mb; ACE_NEW_RETURN (mb, ACE_Message_Block (HTTP_Handler::MAX_REQUEST_SIZE + 1), -1); // Create an HTTP Handler to handle this request HTTP_Handler *handler = this->factory_.create_http_handler (); handler->open (stream.get_handle (), *mb); // Handler is destroyed when the I/O puts the Handler into the // done state. mb->release (); ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) in Synch_Thread_Pool_Task::svc, recycling\n"))); } ACE_NOTREACHED(return 0);}intHTTP_Server::thread_per_request (HTTP_Handler_Factory &factory){ int grp_id = -1; // thread per request // Main thread opens the acceptor if (this->acceptor_.open (ACE_INET_Addr (this->port_), 1, PF_INET, this->backlog_) == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("HTTP_Acceptor::open")), -1); ACE_SOCK_Stream stream; // When we are throttling, this is the amount of time to wait before // checking for runnability again. const ACE_Time_Value wait_time (0, 10); for (;;) { if (this->acceptor_.accept (stream) == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("HTTP_Acceptor::accept")), -1); Thread_Per_Request_Task *t; // Pass grp_id as a constructor param instead of into open. ACE_NEW_RETURN (t, Thread_Per_Request_Task (stream.get_handle (), this->tm_, grp_id, factory), -1); if (t->open () != 0) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("Thread_Per_Request_Task::open")), -1); // Throttling is not allowing too many threads to run away. // Should really use some sort of condition variable here. if (!this->throttle_) continue; // This works because each task has only one thread. while (this->tm_.num_tasks_in_group (grp_id) > this->threads_) this->tm_.wait (&wait_time); } ACE_NOTREACHED(return 0);}Thread_Per_Request_Task::Thread_Per_Request_Task (ACE_HANDLE handle, ACE_Thread_Manager &tm, int &grp_id, HTTP_Handler_Factory &factory) : ACE_Task<ACE_NULL_SYNCH> (&tm), handle_ (handle), grp_id_ (grp_id), factory_ (factory){}// HEY! Add a method to the thread_manager to return total number of// threads managed in all the tasks.intThread_Per_Request_Task::open (void *){ int status = -1; if (this->grp_id_ == -1) status = this->grp_id_ = this->activate (THR_DETACHED | THR_NEW_LWP); else status = this->activate (THR_DETACHED | THR_NEW_LWP, 1, 0, -1, this->grp_id_, 0); if (status == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("Thread_Per_Request_Task::open")), -1); return 0;}intThread_Per_Request_Task::svc (void){ ACE_Message_Block *mb; ACE_NEW_RETURN (mb, ACE_Message_Block (HTTP_Handler::MAX_REQUEST_SIZE + 1), -1); //Synch_HTTP_Handler_Factory factory; HTTP_Handler *handler = this->factory_.create_http_handler (); handler->open (this->handle_, *mb); mb->release (); return 0;}intThread_Per_Request_Task::close (u_long){ ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) Thread_Per_Request_Task::svc, dying\n"))); delete this; return 0;}// Understanding the code below requires understanding of the// WindowsNT asynchronous completion notification mechanism and the// Proactor Pattern.// (1) The application submits an asynchronous I/O request to the// operating system and a special handle with it (Asynchronous// Completion Token).// (2) The operating system commits to performing the I/O request,// while application does its own thing.// (3) Operating system finishes the I/O request and places ACT onto// the I/O Completion Port, which is a queue of finished// asynchronous requests.// (4) The application eventually checks to see if the I/O request// is done by checking the I/O Completion Port, and retrieves the// ACT.intHTTP_Server::asynch_thread_pool (void){// This only works on Win32#if defined (ACE_WIN32) // Create the appropriate acceptor for this concurrency strategy and // an appropriate handler for this I/O strategy ACE_Asynch_Acceptor<Asynch_HTTP_Handler_Factory> acceptor; // Tell the acceptor to listen on this->port_, which makes an // asynchronous I/O request to the OS. if (acceptor.open (ACE_INET_Addr (this->port_), HTTP_Handler::MAX_REQUEST_SIZE + 1) == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE_Asynch_Acceptor::open")), -1); // Create the thread pool. // Register threads with the proactor and thread manager. Asynch_Thread_Pool_Task t (*ACE_Proactor::instance (), this->tm_); // The proactor threads are waiting on the I/O Completion Port. // Wait for the threads to finish. return this->tm_.wait ();#endif /* ACE_WIN32 */ return -1;}// This only works on Win32#if defined (ACE_WIN32)Asynch_Thread_Pool_Task::Asynch_Thread_Pool_Task (ACE_Proactor &proactor, ACE_Thread_Manager &tm) : ACE_Task<ACE_NULL_SYNCH> (&tm), proactor_ (proactor){ if (this->activate () == -1) ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("Asynch_Thread_Pool_Task::open")));}intAsynch_Thread_Pool_Task::svc (void){ for (;;) if (this->proactor_.handle_events () == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE_Proactor::handle_events")), -1); return 0;}#endif /* ACE_WIN32 */// Define the factory function.ACE_SVC_FACTORY_DEFINE (HTTP_Server)// Define the object that describes the service.ACE_STATIC_SVC_DEFINE (HTTP_Server, ACE_TEXT ("HTTP_Server"), ACE_SVC_OBJ_T, &ACE_SVC_NAME (HTTP_Server), ACE_Service_Type::DELETE_THIS | ACE_Service_Type::DELETE_OBJ, 0)#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)template class ACE_LOCK_SOCK_Acceptor<ACE_SYNCH_MUTEX>;#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)#pragma instantiate ACE_LOCK_SOCK_Acceptor<ACE_SYNCH_MUTEX>#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -