system programming practical session 12 reactor. thread-per-client downsides 1.each thread waste...

26
System Programming Practical session 12 Reactor

Post on 20-Dec-2015

230 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

System Programming

Practical session 12

Reactor

Page 2: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

Thread-Per-Client downsides1. Each thread waste resources.

2. Blocking I/O.

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

Page 3: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

Non-Blocking I/O

ServerSocketChannel

SocketChannel

SocketChannel

SocketChannel

SocketChannel

Selector

Server

ConnectionAcceptor

key

ProtocolTask

ConnectionHandler

Page 4: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

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

Page 5: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

BuffersByteBuffer are buffers that hold bytes.

Channels know how to read and write to buffers.

final int NUM_OF_BYTES = 1024;

ByteBuffer buf = ByteBuffer.allocate(NUM_OF_BYTES);

From Channel to Buffer and back

Creating a Buffer

numBytesRead = _socketChannel.read(buf1);

numBytesWritten = _socketChannel.write(buf2);

• Return –1 if channel is closed.

• Update position marker of the buffer.

Page 6: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

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

Page 7: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

select() Method

Blocks until at least one of the channels is ready for the registered event.

selector.select();

A list of SelectionKeys is returned.

Each Selectionkey is associated with one event, and holds the attachment registered with the event.

Page 8: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

Reactor Actors

Reactor – The main class.

• Creates ServerSocket channel

• Registers the Selector

• For each event, invokes the appropriate attachment

• ConnectionAcceptor

• ConnectionHandler

Page 9: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

ConnectionAcceptor

Reactor Actors

accept()

• Creates SocketChanel.

• Register the Selector.

• Creates ConnectionHandler.

Page 10: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

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.

Page 11: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

Reactor Actors

ProtocolTask

• Passes unprocessed input data to message tokenizer.

• Processes each complete message.

• Passes output data to ConnectionHandler.

Page 12: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

Execution example

ServerSocketChannel ssChannel = ServerSocketChannel.open();

ssChannel.configureBlocking( false);

ssChannel.socket().bind(new InetSocketAddress(port));

ssChannel

Selector selector = Selector.open();

selector

ssChannel.register(selector, SelectionKey.OP_ACCEPT, connectionAcceptor);

public class Reactor{

...

 ExecutorService executor = 

Executors.newFixedThreadPool(

_poolSize);

executor

Page 13: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

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

}

Page 14: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

public class ConnectionAcceptor {

public void 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();}

}

}

}

ssChannel

selector

Client connection request

sChannel

sChannel

sChannel

Page 15: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

ssChannel

selector

sChannel

sChannel

sChannel

“Don’t worry”

Page 16: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

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

}

Page 17: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

ssChannel

selector

sChannel

sChannel

sChannel

“Don’t worry”

public class ConnectionHandler {…

public void 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);

}

}

Page 18: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

public class ProtocolTask implements Runnable {

private final Vector<ByteBuffer> _buffers =

new Vector<ByteBuffer>();

public synchronized void run() {

synchronized (_buffers) {

while(_buffers.size() > 0) {

ByteBuffer buf = _buffers.remove(0);

this._tokenizer.addBytes(buf); }

}

while (_tokenizer.hasMessage()) {

}

}

}

public void addBytes(ByteBuffer b) {

synchronized (_buffers) {

_buffers.add(b);

}

}

}

_buffers

Page 19: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

public class ProtocolTask implements Runnable {

private final Vector<ByteBuffer> _buffers =

new Vector<ByteBuffer>();

public synchronized void run() {

synchronized (_buffers) {

while(_buffers.size() > 0) {

ByteBuffer buf = _buffers.remove(0);

this._tokenizer.addBytes(buf); }

}

while (_tokenizer.hasMessage()) {

}

}

}

public void addBytes(ByteBuffer b) {

synchronized (_buffers) {

_buffers.add(b);

}

}

}

_buffers

D o n ’ t w o r r y

_tokenizer

“Don’t worry”

Page 20: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

ssChannel

selector

sChannel

sChannel

sChannel

“be happy\n”

public class ConnectionHandler {…

public void 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);

}

}

Page 21: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

public class ProtocolTask implements Runnable {…

public synchronized void 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) { … }

} } }

public void addBytes(ByteBuffer b) {

synchronized (_buffers) { _buffers.add(b); } }

}

_tokenizer

“Don’t worry be happy\n”

response

“Your message “Don’t

worry be happy” received”

Page 22: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

public class ConnectionHandler{

public synchronized void addOutData(ByteBuffer buf) {

_outData.add(buf);

switchToReadWriteMode();

}

public void switchToReadWriteMode() {

_skey.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);

_data.getSelector().wakeup();

}

}

Page 23: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

ssChannel

selector

sChannel

sChannel

sChannel

Page 24: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

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();

}

}

Page 25: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

“Your message “Don’t worry be

happy” received”

public synchronized void 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

sChannel

Page 26: System Programming Practical session 12 Reactor. Thread-Per-Client downsides 1.Each thread waste resources. 2.Blocking I/O. 3.Vulnerability to denial

public synchronized void 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