Socket::select and SocketReactor improvements

This commit is contained in:
Guenter Obiltschnig 2008-09-21 18:36:40 +00:00
parent 9b636a3fbd
commit 8e58146848
8 changed files with 127 additions and 29 deletions

View File

@ -1,7 +1,7 @@
//
// Socket.h
//
// $Id: //poco/svn/Net/include/Poco/Net/Socket.h#3 $
// $Id: //poco/1.3/Net/include/Poco/Net/Socket.h#3 $
//
// Library: Net
// Package: Sockets
@ -129,6 +129,10 @@ public:
/// * readList contains those sockets ready for reading,
/// * writeList contains those sockets ready for writing,
/// * exceptList contains those sockets with a pending error.
///
/// If the total number of sockets passed in readList, writeList and
/// exceptList is zero, select() will return immediately and the
/// return value will be 0.
bool poll(const Poco::Timespan& timeout, int mode) const;
/// Determines the status of the socket, using a

View File

@ -1,7 +1,7 @@
//
// SocketNotification.h
//
// $Id: //poco/svn/Net/include/Poco/Net/SocketNotification.h#2 $
// $Id: //poco/1.3/Net/include/Poco/Net/SocketNotification.h#2 $
//
// Library: Net
// Package: Reactor
@ -128,6 +128,19 @@ public:
};
class Net_API IdleNotification: public SocketNotification
/// This notification is sent when the SocketReactor does
/// not have any sockets to react to.
{
public:
IdleNotification(SocketReactor* pReactor);
/// Creates the IdleNotification for the given SocketReactor.
~IdleNotification();
/// Destroys the IdleNotification.
};
class Net_API ShutdownNotification: public SocketNotification
/// This notification is sent when the SocketReactor is
/// about to shut down.

View File

@ -1,7 +1,7 @@
//
// SocketReactor.h
//
// $Id: //poco/svn/Net/include/Poco/Net/SocketReactor.h#2 $
// $Id: //poco/1.3/Net/include/Poco/Net/SocketReactor.h#2 $
//
// Library: Net
// Package: Reactor
@ -90,7 +90,8 @@ class Net_API SocketReactor: public Poco::Runnable
/// 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 and ShutdownNotification.
/// ErrorNotification, TimeoutNotification, IdleNotification and
/// ShutdownNotification.
///
/// The ReadableNotification will be dispatched if a socket becomes
/// readable. The WritableNotification will be dispatched if a socket
@ -100,9 +101,17 @@ class Net_API SocketReactor: public Poco::Runnable
/// 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 overridded by subclasses to perform custom
/// 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
@ -174,6 +183,13 @@ protected:
/// 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.
@ -208,6 +224,7 @@ private:
NotificationPtr _pWritableNotification;
NotificationPtr _pErrorNotification;
NotificationPtr _pTimeoutNotification;
NotificationPtr _pIdleNotification;
NotificationPtr _pShutdownNotification;
Poco::FastMutex _mutex;

View File

@ -1,7 +1,7 @@
//
// Socket.cpp
//
// $Id: //poco/svn/Net/src/Socket.cpp#2 $
// $Id: //poco/1.3/Net/src/Socket.cpp#4 $
//
// Library: Net
// Package: Sockets
@ -112,6 +112,7 @@ int Socket::select(SocketList& readList, SocketList& writeList, SocketList& exce
nfd = int(it->sockfd());
FD_SET(it->sockfd(), &fdExcept);
}
if (nfd == 0) return 0;
Poco::Timespan remainingTime(timeout);
int rc;
do

View File

@ -1,7 +1,7 @@
//
// SocketNotification.cpp
//
// $Id: //poco/svn/Net/src/SocketNotification.cpp#2 $
// $Id: //poco/1.3/Net/src/SocketNotification.cpp#2 $
//
// Library: Net
// Package: Reactor
@ -102,6 +102,17 @@ TimeoutNotification::~TimeoutNotification()
}
IdleNotification::IdleNotification(SocketReactor* pReactor):
SocketNotification(pReactor)
{
}
IdleNotification::~IdleNotification()
{
}
ShutdownNotification::ShutdownNotification(SocketReactor* pReactor):
SocketNotification(pReactor)
{

View File

@ -1,7 +1,7 @@
//
// SocketReactor.cpp
//
// $Id: //poco/svn/Net/src/SocketReactor.cpp#2 $
// $Id: //poco/1.3/Net/src/SocketReactor.cpp#2 $
//
// Library: Net
// Package: Reactor
@ -38,6 +38,7 @@
#include "Poco/Net/SocketNotification.h"
#include "Poco/Net/SocketNotifier.h"
#include "Poco/ErrorHandler.h"
#include "Poco/Thread.h"
#include "Poco/Exception.h"
@ -57,6 +58,7 @@ SocketReactor::SocketReactor():
_pWritableNotification(new WritableNotification(this)),
_pErrorNotification(new ErrorNotification(this)),
_pTimeoutNotification(new TimeoutNotification(this)),
_pIdleNotification(new IdleNotification(this)),
_pShutdownNotification(new ShutdownNotification(this))
{
}
@ -69,6 +71,7 @@ SocketReactor::SocketReactor(const Poco::Timespan& timeout):
_pWritableNotification(new WritableNotification(this)),
_pErrorNotification(new ErrorNotification(this)),
_pTimeoutNotification(new TimeoutNotification(this)),
_pIdleNotification(new IdleNotification(this)),
_pShutdownNotification(new ShutdownNotification(this))
{
}
@ -87,31 +90,60 @@ void SocketReactor::run()
while (!_stop)
{
readable.clear();
writable.clear();
except.clear();
try
{
FastMutex::ScopedLock lock(_mutex);
for (EventHandlerMap::iterator it = _handlers.begin(); it != _handlers.end(); ++it)
readable.clear();
writable.clear();
except.clear();
int nSockets = 0;
{
if (it->second->accepts(_pReadableNotification))
readable.push_back(it->first);
if (it->second->accepts(_pWritableNotification))
writable.push_back(it->first);
if (it->second->accepts(_pErrorNotification))
except.push_back(it->first);
FastMutex::ScopedLock lock(_mutex);
for (EventHandlerMap::iterator it = _handlers.begin(); it != _handlers.end(); ++it)
{
if (it->second->accepts(_pReadableNotification))
{
readable.push_back(it->first);
nSockets++;
}
if (it->second->accepts(_pWritableNotification))
{
writable.push_back(it->first);
nSockets++;
}
if (it->second->accepts(_pErrorNotification))
{
except.push_back(it->first);
nSockets++;
}
}
}
if (nSockets == 0)
{
onIdle();
}
else if (Socket::select(readable, writable, except, _timeout))
{
for (Socket::SocketList::iterator it = readable.begin(); it != readable.end(); ++it)
dispatch(*it, _pReadableNotification);
for (Socket::SocketList::iterator it = writable.begin(); it != writable.end(); ++it)
dispatch(*it, _pWritableNotification);
for (Socket::SocketList::iterator it = except.begin(); it != except.end(); ++it)
dispatch(*it, _pErrorNotification);
}
else onTimeout();
}
if (Socket::select(readable, writable, except, _timeout))
catch (Exception& exc)
{
for (Socket::SocketList::iterator it = readable.begin(); it != readable.end(); ++it)
dispatch(*it, _pReadableNotification);
for (Socket::SocketList::iterator it = writable.begin(); it != writable.end(); ++it)
dispatch(*it, _pWritableNotification);
for (Socket::SocketList::iterator it = except.begin(); it != except.end(); ++it)
dispatch(*it, _pErrorNotification);
ErrorHandler::handle(exc);
}
catch (std::exception& exc)
{
ErrorHandler::handle(exc);
}
catch (...)
{
ErrorHandler::handle();
}
else onTimeout();
}
onShutdown();
}
@ -172,6 +204,12 @@ void SocketReactor::onTimeout()
}
void SocketReactor::onIdle()
{
dispatch(_pIdleNotification);
}
void SocketReactor::onShutdown()
{
dispatch(_pShutdownNotification);

View File

@ -1,7 +1,7 @@
//
// SocketTest.cpp
//
// $Id: //poco/svn/Net/testsuite/src/SocketTest.cpp#2 $
// $Id: //poco/1.3/Net/testsuite/src/SocketTest.cpp#2 $
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
@ -425,6 +425,18 @@ void SocketTest::testSelect2()
}
void SocketTest::testSelect3()
{
Socket::SocketList readList;
Socket::SocketList writeList;
Socket::SocketList exceptList;
Timespan timeout(1000);
int rc = Socket::select(readList, writeList, exceptList, timeout);
assert (rc == 0);
}
void SocketTest::setUp()
{
}
@ -452,6 +464,7 @@ CppUnit::Test* SocketTest::suite()
CppUnit_addTest(pSuite, SocketTest, testOptions);
CppUnit_addTest(pSuite, SocketTest, testSelect);
CppUnit_addTest(pSuite, SocketTest, testSelect2);
CppUnit_addTest(pSuite, SocketTest, testSelect3);
return pSuite;
}

View File

@ -1,7 +1,7 @@
//
// SocketTest.h
//
// $Id: //poco/svn/Net/testsuite/src/SocketTest.h#2 $
// $Id: //poco/1.3/Net/testsuite/src/SocketTest.h#2 $
//
// Definition of the SocketTest class.
//
@ -59,6 +59,7 @@ public:
void testOptions();
void testSelect();
void testSelect2();
void testSelect3();
void setUp();
void tearDown();