260 likes | 280 Views
System Programming Practical session 12 Reactor. Thread-Per-Client downsides. Each thread waste resources. Blocking I/O. Vulnerability to denial of service attack. The Reactor design pattern solve these problems. One thread deals with communication .
E N D
System Programming Practical session 12 Reactor
Thread-Per-Client downsides • Each thread waste resources. • Blocking I/O. • Vulnerability to denial of service attack. The Reactor design pattern solve these problems. • One thread deals with communication. • Fixed number of threads deal with work. • communication and work layers are separate and asynchronous. • Non-blocking I/O.
Non-Blocking I/O Server key Selector ConnectionAcceptor ServerSocketChannel SocketChannel ConnectionHandler SocketChannel SocketChannel ProtocolTask SocketChannel
Channels Channels wrap sockets, and allow non-blocking I/O. read(), write() , accept() can be non blocking. Setting up a non-blocking ServerSocketChannel listening on a specific port. int port = 9999; ServerSocketChannel ssChannel = serverSocketChannel.open(); ssChannel.configureBlocking(false); ssChannel.socket().bind(new InetSocketAddress(port));
Buffers ByteBuffer are buffers that hold bytes. Channels know how to read and write to buffers. Creating a Buffer final int NUM_OF_BYTES = 1024; ByteBuffer buf = ByteBuffer.allocate(NUM_OF_BYTES); From Channel to Buffer and back numBytesRead = _socketChannel.read(buf1); numBytesWritten = _socketChannel.write(buf2); • Return –1 if channel is closed. • Update position marker of the buffer.
Selector The selector monitors the channels for new events (new data arrived, new connection). A Selector is registered to each channel with an attachment to handle the event. An appropriate attachment is invoked for each new event. Selector selector = Selector.open(); Object anAttachment = new Object(); socketChannel.register(selector, SelectionKey.OP_READ, anAttachmemt);
select() Method selector.select(); Blocks until at least one of the channels is ready for the registered event. A list of SelectionKeys is returned. Each Selectionkey is associated with one event, and holds the attachment registered with the event.
Reactor Actors • Reactor – The main class. • Creates ServerSocket channel • Registers the Selector • For each event, invokes the appropriate attachment • ConnectionAcceptor • ConnectionHandler
Reactor Actors ConnectionAcceptor • accept() • Creates SocketChanel. • Register the Selector. • Creates ConnectionHandler.
Reactor Actors • ConnectionHandler • Read() • Reads new data from channel. • Adds ProtoclTask for yet unprocessed input data to a fixed thread pool. • Write() • Receives output data from ProtocolTask. • Writes the data to the channel.
Reactor Actors • ProtocolTask • Passes unprocessed input data to message tokenizer. • Processes each complete message. • Passes output data to ConnectionHandler.
Execution example publicclass Reactor{ ... selector ssChannel ServerSocketChannel ssChannel = ServerSocketChannel.open(); ssChannel.configureBlocking( false); ssChannel.socket().bind(new InetSocketAddress(port)); Selector selector = Selector.open(); ssChannel.register(selector, SelectionKey.OP_ACCEPT, connectionAcceptor); ExecutorServiceexecutor= Executors.newFixedThreadPool( _poolSize); executor
while (_shouldRun && selector.isOpen()) { try { selector.select(); } catch (IOException e) {…} Iterator it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey selKey = (SelectionKey) it.next(); it.remove(); if (selKey.isValid() && selKey.isAcceptable()) { ConnectionAcceptor acceptor = (ConnectionAcceptor) selKey.attachment(); try { acceptor.accept(); } catch (IOException e) {…) if (selKey.isValid() && selKey.isReadable()) { //Handle reading… } if (selKey.isValid() && selKey.isWritable()) { //Handle writing… } }
publicclass ConnectionAcceptor { … publicvoid accept() { SocketChannel sChannel = _ssChannel.accept(); if (sChannel != null) { sChannel.configureBlocking(false); SelectionKey key =sChannel.register( _data.getSelector(), 0); ConnectionHandler handler = ConnectionHandler.create(sChannel, _data, key); handler.switchToReadOnlyMode();} } } } Client connection request selector ssChannel sChannel sChannel sChannel
selector ssChannel “Don’t worry” sChannel sChannel sChannel
while (_shouldRun && selector.isOpen()) { try { selector.select(); } catch (IOException e) {…} Iterator it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey selKey = (SelectionKey) it.next(); it.remove(); if (selKey.isValid() && selKey.isAcceptable()) { … } if (selKey.isValid() && selKey.isReadable()) { ConnectionHandler handler = (ConnectionHandler) selKey.attachment(); handler.read(); } if (selKey.isValid() && selKey.isWritable()) { //Handle writing… } }
publicclass ConnectionHandler {… publicvoid read() { ByteBuffer buf = ByteBuffer.allocate(BUFFER_SIZE); int numBytesRead = 0; try { numBytesRead =sChannel.read(buf); } catch (IOException e) { numBytesRead = -1; } if (numBytesRead == -1) { closeConnection(); _protocol.connectionTerminated(); return; } buf.flip(); _task.addBytes(buf); _data.getExecutor().execute(_task); } } selector ssChannel “Don’t worry” sChannel sChannel sChannel
publicclass ProtocolTask implements Runnable { privatefinal Vector<ByteBuffer> _buffers = new Vector<ByteBuffer>(); … publicsynchronizedvoid run() { synchronized (_buffers) { while(_buffers.size() > 0) { ByteBuffer buf = _buffers.remove(0); this._tokenizer.addBytes(buf); } } while (_tokenizer.hasMessage()) { … } } } publicvoid addBytes(ByteBuffer b) { synchronized (_buffers) { _buffers.add(b); } } } _buffers
publicclass ProtocolTask implements Runnable { privatefinal Vector<ByteBuffer> _buffers = new Vector<ByteBuffer>(); … publicsynchronizedvoid run() { synchronized (_buffers) { while(_buffers.size() > 0) { ByteBuffer buf = _buffers.remove(0); this._tokenizer.addBytes(buf); } } while (_tokenizer.hasMessage()) { … } } } publicvoid addBytes(ByteBuffer b) { synchronized (_buffers) { _buffers.add(b); } } } _tokenizer “Don’t worry” _buffers D o n ’ t w o r r y
publicclass ConnectionHandler {… publicvoid read() { ByteBuffer buf = ByteBuffer.allocate(BUFFER_SIZE); int numBytesRead = 0; try { numBytesRead =sChannel.read(buf); } catch (IOException e) { numBytesRead = -1; } if (numBytesRead == -1) { closeConnection(); _protocol.connectionTerminated(); return; } buf.flip(); _task.addBytes(buf); _data.getExecutor().execute(_task); } } selector ssChannel “be happy\n” sChannel sChannel sChannel
publicclass ProtocolTask implements Runnable {… … publicsynchronizedvoid run() { synchronized (_buffers) { while(_buffers.size() > 0) { ByteBuffer buf = _buffers.remove(0); this._tokenizer.addBytes(buf); } } while (_tokenizer.hasMessage()) { String msg = _tokenizer.nextMessage(); String response = this._protocol.processMessage(msg); if (response != null) { try { ByteBuffer bytes = _tokenizer.getBytesForMessage(response); this._handler.addOutData(bytes); } catch (CharacterCodingException e) { … } } } } publicvoid addBytes(ByteBuffer b) { synchronized (_buffers) { _buffers.add(b); } } } _tokenizer “Don’t worry be happy\n” response “Your message“Don’t worry be happy” received”
publicclass ConnectionHandler{ … publicsynchronizedvoid addOutData(ByteBuffer buf) { _outData.add(buf); switchToReadWriteMode(); } publicvoid switchToReadWriteMode() { _skey.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); _data.getSelector().wakeup(); } }
selector ssChannel sChannel sChannel sChannel
while (_shouldRun && selector.isOpen()) { try { selector.select(); } catch (IOException e) {…} Iterator it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey selKey = (SelectionKey) it.next(); it.remove(); if (selKey.isValid() && selKey.isAcceptable()) { … } if (selKey.isValid() && selKey.isReadable()){…} if (selKey.isValid() && selKey.isWritable()){ ConnectionHandler handler = (ConnectionHandler) selKey.attachment(); handler.write(); } }
publicsynchronizedvoid write() { if (_outData.size() == 0) { switchToReadOnlyMode(); return; } ByteBuffer buf = _outData.remove(0); if (buf.remaining() != 0) { try { _sChannel.write(buf); } catch (IOException e) {…} if (buf.remaining() != 0) { _outData.add(0, buf);} } if (_protocol.shouldClose()) { switchToWriteOnlyMode(); if (buf.remaining() == 0) { closeConnection(); } } } ssChannel selector “Your message “Don’t worry be happy” received” sChannel sChannel sChannel
publicsynchronizedvoid write() { if (_outData.size() == 0) { switchToReadOnlyMode(); return; } ByteBuffer buf = _outData.remove(0); if (buf.remaining() != 0) { try { _sChannel.write(buf); } catch (IOException e) {…} if (buf.remaining() != 0) { _outData.add(0, buf);} } if (_protocol.shouldClose()) { switchToWriteOnlyMode(); if (buf.remaining() == 0) { closeConnection(); } } } ssChannel selector sChannel sChannel