
Reactor/Реактор
Категория: Шаблоны параллельного программирования
Описание
Шаблон Реактор– это шаблон проектирования для синхронного демультиплескриования одновременно прибывающих событий.
Уместность применения
Шаблон следует применять, если требуется получать сообщения/запросы/соедиения от параллельно работающих клиентов и обрабатывать эти сообщения последовательно, используя обработчики событий.
Преимущества, достигаемые при применении шаблона
Позволяет избежать проблемы создания потоков для всех входящих сообщений/запросов/соедиений.
Недостатки шаблона
Приложения, написанные с помощью наблона Реактор, сложно отлаживать, поскольку имеется хаотичный поток управления между инфраструктурой системы и вызовами метода на обработчиках приложения.
Детали реализации
Классы
public interface ISynchronousEventDemultiplexer
{
IList<TcpListener> Select(ICollection<TcpListener> listeners);
}
public class SynchronousEventDemultiplexer : ISynchronousEventDemultiplexer
{
public IList<TcpListener> Select(ICollection<TcpListener> listeners)
{
var tcpListeners =
new List<TcpListener>(from listener in listeners
where listener.Pending()
select listener);
return tcpListeners;
}
}
public interface IEventHandler
{
void HandleEvent(byte[] data);
TcpListener GetHandler();
}
public class MessageEventHandler : IEventHandler
{
private readonly TcpListener _listener;
public MessageEventHandler(IPAddress ipAddress, int port)
{
_listener = new TcpListener(ipAddress, port);
}
public void HandleEvent(byte[] data)
{
string message = Encoding.UTF8.GetString(data);
}
public TcpListener GetHandler()
{
return _listener;
}
}
public interface IReactor
{
void RegisterHandle(IEventHandler eventHandler);
void RemoveHandle(IEventHandler eventHandler);
void HandleEvents();
}
public class Reactor : IReactor
{
ISynchronousEventDemultiplexer _synchronousEventDemultiplexer;
IDictionary<TcpListener, IEventHandler> _handlers;
public Reactor(ISynchronousEventDemultiplexer synchronousEventDemultiplexer)
{
_synchronousEventDemultiplexer = synchronousEventDemultiplexer;
_handlers = new Dictionary<TcpListener, IEventHandler>();
}
public void RegisterHandle(IEventHandler eventHandler)
{
_handlers.Add(eventHandler.GetHandler(), eventHandler);
}
public void RemoveHandle(IEventHandler eventHandler)
{
_handlers.Remove(eventHandler.GetHandler());
}
public void HandleEvents()
{
while (true)
{
IList<TcpListener> listeners = _synchronousEventDemultiplexer.Select(_handlers.Keys);
foreach (TcpListener listener in listeners)
{
int dataReceived = 0;
byte[] buffer = new byte[1];
IList<byte> data = new List<byte>();
Socket socket = listener.AcceptSocket();
do
{
dataReceived = socket.Receive(buffer);
if (dataReceived > 0)
{
data.Add(buffer[0]);
}
} while (dataReceived > 0);
socket.Close();
_handlers[listener].HandleEvent(data.ToArray());
}
}
}
}
Программа:
static void Main(string[] args)
{
IEventHandler client1 = new MessageEventHandler(IPAddress.Parse("123.123.123.123"), 123);
IEventHandler client2 = new MessageEventHandler(IPAddress.Parse("234.234.234.234"), 123);
IEventHandler client3 = new MessageEventHandler(IPAddress.Parse("125.125.125.125"), 123);
ISynchronousEventDemultiplexer synchronousEventDemultiplexer = new SynchronousEventDemultiplexer();
Reactor dispatcher = new Reactor(synchronousEventDemultiplexer);
dispatcher.RegisterHandle(client1);
dispatcher.RegisterHandle(client2);
dispatcher.RegisterHandle(client3);
dispatcher.HandleEvents();
}
UML-диаграмма
Диаграмма классов:
Диаграмма последовательности
Литература
http://www.robertsindall.co.uk/blog/the-reactor-pattern-using-c-sharp/
Reactor An Object Behavioral Pattern for Demultiplexing and Dispatching Handles for Synchronous Douglas C. Schmidt, University of California, Irvine, CA 92697, USA