1 / 26

System Programming Practical session 12 Reactor

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 .

evillarreal
Download Presentation

System Programming Practical session 12 Reactor

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. System Programming Practical session 12 Reactor

  2. 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.

  3. Non-Blocking I/O Server key Selector ConnectionAcceptor ServerSocketChannel SocketChannel ConnectionHandler SocketChannel SocketChannel ProtocolTask SocketChannel

  4. 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));

  5. 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.

  6. 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);

  7. 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.

  8. Reactor Actors • Reactor – The main class. • Creates ServerSocket channel • Registers the Selector • For each event, invokes the appropriate attachment • ConnectionAcceptor • ConnectionHandler

  9. Reactor Actors ConnectionAcceptor • accept() • Creates SocketChanel. • Register the Selector. • Creates ConnectionHandler.

  10. 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.

  11. Reactor Actors • ProtocolTask • Passes unprocessed input data to message tokenizer. • Processes each complete message. • Passes output data to ConnectionHandler.

  12. 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

  13. 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… } }

  14. 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

  15. selector ssChannel “Don’t worry” sChannel sChannel sChannel

  16. 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… } }

  17. 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

  18. 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

  19. 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

  20. 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

  21. 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”

  22. publicclass ConnectionHandler{ … publicsynchronizedvoid addOutData(ByteBuffer buf) { _outData.add(buf); switchToReadWriteMode(); } publicvoid switchToReadWriteMode() { _skey.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); _data.getSelector().wakeup(); } }

  23. selector ssChannel sChannel sChannel sChannel

  24. 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(); } }

  25. 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

  26. 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

More Related