poco/Net/include/Poco/Net/SocketReactor.h
2012-05-04 03:39:24 +00:00

249 lines
9.0 KiB
C++

//
// SocketReactor.h
//
// $Id: //poco/1.4/Net/include/Poco/Net/SocketReactor.h#1 $
//
// Library: Net
// Package: Reactor
// Module: SocketReactor
//
// Definition of the SocketReactor class.
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#ifndef Net_SocketReactor_INCLUDED
#define Net_SocketReactor_INCLUDED
#include "Poco/Net/Net.h"
#include "Poco/Net/Socket.h"
#include "Poco/Runnable.h"
#include "Poco/Timespan.h"
#include "Poco/Observer.h"
#include "Poco/AutoPtr.h"
#include <map>
namespace Poco {
namespace Net {
class Socket;
class SocketNotification;
class SocketNotifier;
class Net_API SocketReactor: public Poco::Runnable
/// This class, which is part of the Reactor pattern,
/// implements the "Initiation Dispatcher".
///
/// The Reactor pattern has been described in the book
/// "Pattern Languages of Program Design" by Jim Coplien
/// and Douglas C. Schmidt (Addison Wesley, 1995).
///
/// The Reactor design pattern handles service requests that
/// are delivered concurrently to an application by one or more
/// clients. Each service in an application may consist of several
/// methods and is represented by a separate event handler. The event
/// handler is responsible for servicing service-specific requests.
/// The SocketReactor dispatches the event handlers.
///
/// Event handlers (any class can be an event handler - there
/// is no base class for event handlers) can be registered
/// with the addEventHandler() method and deregistered with
/// the removeEventHandler() method.
///
/// An event handler is always registered for a certain socket,
/// which is given in the call to addEventHandler(). Any method
/// of the event handler class can be registered to handle the
/// event - the only requirement is that the method takes
/// a pointer to an instance of SocketNotification (or a subclass of it)
/// as argument.
///
/// Once started, the SocketReactor waits for events
/// on the registered sockets, using Socket::select().
/// If an event is detected, the corresponding event handler
/// is invoked. There are five event types (and corresponding
/// notification classes) defined: ReadableNotification, WritableNotification,
/// ErrorNotification, TimeoutNotification, IdleNotification and
/// ShutdownNotification.
///
/// The ReadableNotification will be dispatched if a socket becomes
/// readable. The WritableNotification will be dispatched if a socket
/// becomes writable. The ErrorNotification will be dispatched if
/// there is an error condition on a socket.
///
/// If the timeout expires and no event has occured, a
/// TimeoutNotification will be dispatched to all event handlers
/// registered for it. This is done in the onTimeout() method
/// which can be overridden by subclasses to perform custom
/// timeout processing.
///
/// If there are no sockets for the SocketReactor to pass to
/// Socket::select(), an IdleNotification will be dispatched to
/// all event handlers registered for it. This is done in the
/// onIdle() method which can be overridden by subclasses
/// to perform custom idle processing. Since onIdle() will be
/// called repeatedly in a loop, it is recommended to do a
/// short sleep or yield in the event handler.
///
/// Finally, when the SocketReactor is about to shut down (as a result
/// of stop() being called), it dispatches a ShutdownNotification
/// to all event handlers. This is done in the onShutdown() method
/// which can be overridded by subclasses to perform custom
/// shutdown processing.
///
/// The SocketReactor is implemented so that it can
/// run in its own thread. It is also possible to run
/// multiple SocketReactors in parallel, as long as
/// they work on different sockets.
///
/// It is safe to call addEventHandler() and removeEventHandler()
/// from another thread while the SocketReactor is running. Also,
/// it is safe to call addEventHandler() and removeEventHandler()
/// from event handlers.
{
public:
SocketReactor();
/// Creates the SocketReactor.
explicit SocketReactor(const Poco::Timespan& timeout);
/// Creates the SocketReactor, using the given timeout.
virtual ~SocketReactor();
/// Destroys the SocketReactor.
void run();
/// Runs the SocketReactor. The reactor will run
/// until stop() is called (in a separate thread).
void stop();
/// Stops the SocketReactor.
///
/// The reactor will be stopped when the next event
/// (including a timeout event) occurs.
void setTimeout(const Poco::Timespan& timeout);
/// Sets the timeout.
///
/// If no other event occurs for the given timeout
/// interval, a timeout event is sent to all event listeners.
///
/// The default timeout is 250 milliseconds;
///
/// The timeout is passed to the Socket::select()
/// method.
const Poco::Timespan& getTimeout() const;
/// Returns the timeout.
void addEventHandler(const Socket& socket, const Poco::AbstractObserver& observer);
/// Registers an event handler with the SocketReactor.
///
/// Usage:
/// Poco::Observer<MyEventHandler, SocketNotification> obs(*this, &MyEventHandler::handleMyEvent);
/// reactor.addEventHandler(obs);
bool hasEventHandler(const Socket& socket, const Poco::AbstractObserver& observer);
/// Returns true if the observer is reistered with SocketReactor for the given socket.
void removeEventHandler(const Socket& socket, const Poco::AbstractObserver& observer);
/// Unregisters an event handler with the SocketReactor.
///
/// Usage:
/// Poco::Observer<MyEventHandler, SocketNotification> obs(*this, &MyEventHandler::handleMyEvent);
/// reactor.removeEventHandler(obs);
protected:
virtual void onTimeout();
/// Called if the timeout expires and no other events are available.
///
/// Can be overridden by subclasses. The default implementation
/// dispatches the TimeoutNotification and thus should be called by overriding
/// implementations.
virtual void onIdle();
/// Called if no sockets are available to call select() on.
///
/// Can be overridden by subclasses. The default implementation
/// dispatches the IdleNotification and thus should be called by overriding
/// implementations.
virtual void onShutdown();
/// Called when the SocketReactor is about to terminate.
///
/// Can be overridden by subclasses. The default implementation
/// dispatches the ShutdownNotification and thus should be called by overriding
/// implementations.
virtual void onBusy();
/// Called when the SocketReactor is busy and at least one notification
/// has been dispatched.
///
/// Can be overridden by subclasses to perform additional
/// periodic tasks. The default implementation does nothing.
void dispatch(const Socket& socket, SocketNotification* pNotification);
/// Dispatches the given notification to all observers
/// registered for the given socket.
void dispatch(SocketNotification* pNotification);
/// Dispatches the given notification to all observers.
private:
typedef Poco::AutoPtr<SocketNotifier> NotifierPtr;
typedef Poco::AutoPtr<SocketNotification> NotificationPtr;
typedef std::map<Socket, NotifierPtr> EventHandlerMap;
void dispatch(NotifierPtr& pNotifier, SocketNotification* pNotification);
enum
{
DEFAULT_TIMEOUT = 250000
};
bool _stop;
Poco::Timespan _timeout;
EventHandlerMap _handlers;
NotificationPtr _pReadableNotification;
NotificationPtr _pWritableNotification;
NotificationPtr _pErrorNotification;
NotificationPtr _pTimeoutNotification;
NotificationPtr _pIdleNotification;
NotificationPtr _pShutdownNotification;
Poco::FastMutex _mutex;
friend class SocketNotifier;
};
} } // namespace Poco::Net
#endif // Net_SocketReactor_INCLUDED