Practical Session 11 Multi ClientServer Java NIO Supporting

  • Slides: 22
Download presentation
Practical Session 11 Multi Client-Server Java NIO

Practical Session 11 Multi Client-Server Java NIO

Supporting Multiple Clients • The basic flow of logic in such a server is

Supporting Multiple Clients • The basic flow of logic in such a server is this: while (true) { accept a connection; create a thread to deal with the client; } • The threads from and writes to the client connection as necessary.

The Server Interface • interface Server. Protocol: – String process. Message(String msg); – boolean

The Server Interface • interface Server. Protocol: – String process. Message(String msg); – boolean is. End(String msg); • In order to organize the work of the Server, and to allow several protocols, we create an interface: – process. Message: a function that decides what to do with the content received. – is. End: returns true if the message equals our ‘exit’ command.

Connection. Handler • In order to allow more than one client to connect to

Connection. Handler • In order to allow more than one client to connect to our server, we need to run each connection in its own thread. • Connection. Handler is a Runnable that handles one connection. • Each client that wishes to connect to our server initiates the connection. • The server accepts the connection from the client. • The socket returned is sent to the Connection. Handler object. • Connection. Handler is run as a Thread. • Server goes back to blocking mode, waiting for a new connection.

Multi. Client – Server Implementation • Server. Protocol [Interface] – process. Message – is.

Multi. Client – Server Implementation • Server. Protocol [Interface] – process. Message – is. End • Echo. Protocol implements Server. Protocol – process. Message: message received is returned – is. End: returns true if message is ‘bye’ • Connection. Handler [Runnable] – Receives messages from client [msg = in. read. Line()] – Processes message [using process()] using Echo. Protocol • If message is ‘bye’, exits thread [protocol. is. End(msg)] • Else, message is sent back to client [out. println(response)] – Sends returned result from processing to client. • Multiple. Client. Protocol. Server [Runnable] – Our server – runs as a thread – Creates Server. Socket, listens to a port – Runs Connection. Handler in a thread once accept() returns a socket. http: //www. cs. bgu. ac. il/~spl 141/Practical. Session 11/Multiple. Client. Protocol. Server

Java Non-blocking IO • In our examples, the server gets stuck on – msg

Java Non-blocking IO • In our examples, the server gets stuck on – msg = in. read. Line() – client. Socket = server. Socket. accept() – out. println(msg) //writing faster than the other side can read • You cannot do something else while these methods are blocking. (process client messages, handle other clients etc. ).

Java Non-blocking IO • Solution? java. nio. • The package is an efficient Input.

Java Non-blocking IO • Solution? java. nio. • The package is an efficient Input. Output package, which supports Non-blocking IO. • NIO Concepts: – Channels – Buffers – Selectors • Tutorial: http: //tutorials. jenkov. com/java-nio/index. html

Channels [our sockets] • An Object you can read from and write to. •

Channels [our sockets] • An Object you can read from and write to. • Channels can be either blocking (by default) or non-blocking. • Socket. Channel: – http: //docs. oracle. com/javase/1. 4. 2/docs/api/java/nio/channels/Socket. Channel. html – Same as regular Socket object. – Difference: read(), write() can be non-blocking. • Server. Socket. Channel: – http: //docs. oracle. com/javase/1. 4. 2/docs/api/java/nio/channels/Server. Socket. Channel. html • Does not block until a client – accept() returns Socket. Channel connects. – Same as regular Server. Socket object. • Checks if a client is trying to connect, if so returns a new – Difference: accept() can be non-blocking. socket, otherwise returns null!

Setting up Server. Socket. Channel and Socket. Channel • Server. Socket. Channel : –

Setting up Server. Socket. Channel and Socket. Channel • Server. Socket. Channel : – – int port = 9999; Server. Socket. Channel ss. Channel = Server. Socket. Channel. open(); ss. Channel. configure. Blocking(false); ss. Channel. socket(). bind(new Inet. Socket. Address(port)); • Socket. Channel: – Socket. Channel s. Channel=Socket. Channel. open(); – s. Channel. connect(new Inet. Socket. Address("host/ip", 9999)); – s. Channel. configure. Blocking(false); http: //docs. oracle. com/javase/1. 4. 2/docs/api/java/net/Inet. Socket. Address. html

Buffers [our containers] • The objects which hold the data to be sent and

Buffers [our containers] • The objects which hold the data to be sent and data received. • Channels know how to read and write into Buffers, and buffers can read and write into other buffers. • Java NIO comes with the following Buffer types: – – – – Byte. Buffer Char. Buffer Double. Buffer Float. Buffer Int. Buffer Long. Buffer Short. Buffer http: //docs. oracle. com/javase/1. 4. 2/docs/api/java/nio/Byte. Buffer. html

Creating Buffers • We'll be using Byte. Buffer. • These are buffers that hold

Creating Buffers • We'll be using Byte. Buffer. • These are buffers that hold bytes. • Creating a new Byte. Buffer: [Method I] – final int NUM_OF_BYTES = 1024; – Byte. Buffer buffer = Byte. Buffer. allocate(NUM_OF_BYTES); • Creating a new Byte. Buffer: [Method II] – String message = “Sentence to write into buffer”; – Byte. Buffer buffer = Byte. Buffer. wrap(message. get. Bytes(), ”UTF-8”);

Buffer Markers • • Each buffer has capacity, limit, and position markers. Capacity: –

Buffer Markers • • Each buffer has capacity, limit, and position markers. Capacity: – – – • Being a memory block, a Buffer has a certain fixed size, also called its "capacity". You can only write capacity bytes, longs, chars etc. into the Buffer. Once the Buffer is full, you need to empty it (read the data, or clear it) before you can write more data into it. Position: – Writing data to buffer: • • • – Reading data from buffer: • • • Limit: – When you flip a Buffer from writing mode to reading mode, the position is reset to 0. As you read data from the Buffer you do so from position, and position is advanced to next position to read. In write mode: • • – Initially the position is 0. When a byte, long etc. has been written into the Buffer the position is advanced to point to the next cell in the buffer to insert data into. Position can maximally become capacity - 1. The limit of a Buffer is the limit of how much data you can write into the buffer. The limit is equal to the capacity of the Buffer. When flipping the Buffer into read mode: • • • The limit means the limit of how much data you can read from the buffer. When flipping a Buffer into read mode, limit is set to write position of the write mode. In other words, you can read as many bytes as were written (limit is set to the number of bytes written, which is marked by position).

Illustration

Illustration

Usage Example

Usage Example

read/write operations •

read/write operations •

Buffer Flipping • The flip() method switches a Buffer from writing mode to reading

Buffer Flipping • The flip() method switches a Buffer from writing mode to reading mode. • Calling flip() sets the position back to 0, and sets the limit to where position just was. • The position marker now marks the reading position, and limit marks how many bytes were written into the buffer - the limit of how many bytes, chars etc. that can be read. • Example: – – You create a Byte. Buffer. Write data into the buffer. Flip() Send the buffer to the channel.

Buffer IO Operations • Reading from a channel to a buffer: num. Bytes. Read

Buffer IO Operations • Reading from a channel to a buffer: num. Bytes. Read = socket. Channel. read(buf); – Contents found in socket. Channel are read from their internal container object to our buffer. • Writing from a buffer to a channel: num. Bytes. Written = socket. Channel. write(buf); – Contents from our buf object are written to the socket. Channel’s internal container to be sent. • If read or write returns -1, it means that the channel is closed. • Read and write operations on Buffers update the position marker accordingly.

More Byte. Buffer Methods • clear(): – Makes a buffer ready for a new

More Byte. Buffer Methods • clear(): – Makes a buffer ready for a new sequence of channel-read or relative put operations. – Sets the limit to the capacity. – Sets the position to zero. • rewind(): – Makes a buffer ready for re-reading the data that it already contains. – Leaves the limit unchanged. – Sets the position to zero.

String. Message. Tokenizer Interface • void add. Bytes(Byte. Buffer bytes); – Receives a Buffer

String. Message. Tokenizer Interface • void add. Bytes(Byte. Buffer bytes); – Receives a Buffer of bytes containing data to be converted to chars. • boolean has. Message(); • Is there a complete message ready? • String next. Message(); – Get the next complete message if it exists, advancing the tokenizer to the next message.

Fixed. Separator. Message. Tokenizer • Fixed. Separator. Message. Tokenizer(String separator, Charset charset) – The

Fixed. Separator. Message. Tokenizer • Fixed. Separator. Message. Tokenizer(String separator, Charset charset) – The constructor. – Between two messages in the buffer we have a separator. – Messages are encoded [chars to bytes] and decoded [bytes to chars] using the given charset [ASCII, UTF-8] • public synchronized void add. Bytes(Byte. Buffer bytes): – Array of bytes received is converted to string and concatenated to the ones before it. • public synchronized boolean has. Message(): – Checks if the buffer has a complete message, if so true, otherwise false. [done by checking if the separator exists in the string array] • public synchronized String next. Message() – Returns the next complete message in the buffer.

NIO Echo Client • http: //www. cs. bgu. ac. il/~spl 141/Practical. Session 10/NIOEcho. C

NIO Echo Client • http: //www. cs. bgu. ac. il/~spl 141/Practical. Session 10/NIOEcho. C lient

C++ Echo Client • Connect a socket to a host and port: boost: :

C++ Echo Client • Connect a socket to a host and port: boost: : asio: : ip: : tcp: : socket_; boost: : asio: : ip: : tcp: : endpoint(boost: : asio: : ip: : address: : from_string(host_), port_); boost: : system: : error_code error; socket_. connect(endpoint, error); • Read from socket: boost: : asio: : buffer(starting. Pointer, Size. To. Read. In. Bytes, exception) //exception is optional //tmp holds the number of bytes read so far; bytes: an array of chars to read the received bytes from socket_. read_some(boost: : asio: : buffer(bytes+tmp, bytes. To. Read-tmp), error) • Write to socket: socket_. write_some(boost: : asio: : buffer(bytes + tmp, bytes. To. Write - tmp), error) • Example: – 05_Boost_Echo_Client