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 // 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 // Library: Net
// Package: Sockets // Package: Sockets
@ -129,6 +129,10 @@ public:
/// * readList contains those sockets ready for reading, /// * readList contains those sockets ready for reading,
/// * writeList contains those sockets ready for writing, /// * writeList contains those sockets ready for writing,
/// * exceptList contains those sockets with a pending error. /// * 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; bool poll(const Poco::Timespan& timeout, int mode) const;
/// Determines the status of the socket, using a /// Determines the status of the socket, using a

View File

@ -1,7 +1,7 @@
// //
// SocketNotification.h // 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 // Library: Net
// Package: Reactor // 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 class Net_API ShutdownNotification: public SocketNotification
/// This notification is sent when the SocketReactor is /// This notification is sent when the SocketReactor is
/// about to shut down. /// about to shut down.

View File

@ -1,7 +1,7 @@
// //
// SocketReactor.h // 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 // Library: Net
// Package: Reactor // Package: Reactor
@ -90,7 +90,8 @@ class Net_API SocketReactor: public Poco::Runnable
/// If an event is detected, the corresponding event handler /// If an event is detected, the corresponding event handler
/// is invoked. There are five event types (and corresponding /// is invoked. There are five event types (and corresponding
/// notification classes) defined: ReadableNotification, WritableNotification, /// notification classes) defined: ReadableNotification, WritableNotification,
/// ErrorNotification, TimeoutNotification and ShutdownNotification. /// ErrorNotification, TimeoutNotification, IdleNotification and
/// ShutdownNotification.
/// ///
/// The ReadableNotification will be dispatched if a socket becomes /// The ReadableNotification will be dispatched if a socket becomes
/// readable. The WritableNotification will be dispatched if a socket /// 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 /// If the timeout expires and no event has occured, a
/// TimeoutNotification will be dispatched to all event handlers /// TimeoutNotification will be dispatched to all event handlers
/// registered for it. This is done in the onTimeout() method /// 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. /// 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 /// Finally, when the SocketReactor is about to shut down (as a result
/// of stop() being called), it dispatches a ShutdownNotification /// of stop() being called), it dispatches a ShutdownNotification
/// to all event handlers. This is done in the onShutdown() method /// to all event handlers. This is done in the onShutdown() method
@ -174,6 +183,13 @@ protected:
/// Can be overridden by subclasses. The default implementation /// Can be overridden by subclasses. The default implementation
/// dispatches the TimeoutNotification and thus should be called by overriding /// dispatches the TimeoutNotification and thus should be called by overriding
/// implementations. /// 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(); virtual void onShutdown();
/// Called when the SocketReactor is about to terminate. /// Called when the SocketReactor is about to terminate.
@ -208,6 +224,7 @@ private:
NotificationPtr _pWritableNotification; NotificationPtr _pWritableNotification;
NotificationPtr _pErrorNotification; NotificationPtr _pErrorNotification;
NotificationPtr _pTimeoutNotification; NotificationPtr _pTimeoutNotification;
NotificationPtr _pIdleNotification;
NotificationPtr _pShutdownNotification; NotificationPtr _pShutdownNotification;
Poco::FastMutex _mutex; Poco::FastMutex _mutex;

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
// //
// SocketTest.cpp // 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. // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors. // 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() void SocketTest::setUp()
{ {
} }
@ -452,6 +464,7 @@ CppUnit::Test* SocketTest::suite()
CppUnit_addTest(pSuite, SocketTest, testOptions); CppUnit_addTest(pSuite, SocketTest, testOptions);
CppUnit_addTest(pSuite, SocketTest, testSelect); CppUnit_addTest(pSuite, SocketTest, testSelect);
CppUnit_addTest(pSuite, SocketTest, testSelect2); CppUnit_addTest(pSuite, SocketTest, testSelect2);
CppUnit_addTest(pSuite, SocketTest, testSelect3);
return pSuite; return pSuite;
} }

View File

@ -1,7 +1,7 @@
// //
// SocketTest.h // 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. // Definition of the SocketTest class.
// //
@ -59,6 +59,7 @@ public:
void testOptions(); void testOptions();
void testSelect(); void testSelect();
void testSelect2(); void testSelect2();
void testSelect3();
void setUp(); void setUp();
void tearDown(); void tearDown();