TCP non bloquant (2/3)

Better non-blocking TCP adder

The goal of this exercise is to write a server for the Sum protocol from ex. 1 of the previous TD. Contrary to the case of ex. 1, we seek to write a sever that may be have simultaneously OP_READ and OP_WRITE as operations of interest.

Sum protocol
The client sends two int (4 bytes) in Big Endian. The server responds with an int in Big Endian, corresponding to the sum of the received integers. These exchanges continue until the client closes the connection for writing.

Starting from the draft ServerSumBetter.java, write a server the the Sum protocol.

For this server, the class Context will contain two ByteBuffer: one for reading and one for writing. The method process is used to transfer from the input ByteBuffer to the output ByteBuffer.

static private class Context {

  final private SelectionKey key;
  final private SocketChannel sc;
  final private ByteBuffer bbin = ByteBuffer.allocate(BUFFER_SIZE);
  final private ByteBuffer bbout = ByteBuffer.allocate(BUFFER_SIZE);
  private boolean closed = false;

  private Context(SelectionKey key){
      this.key = key;
      this.sc = (SocketChannel) key.channel();
  }

  private void process() {
    // TODO
  }

  private void updateInterestOps() {
    // TODO
  }

  private void doRead() throws IOException {
    // TODO 
  }

  private void doWrite() throws IOException {
    // TODO
  }

}  

The jar ClientSumChrono.jar times the time it takes for a client to perform 100 000 sums.

Time your servers ServerSumBetter and ServerSum and compare their respective times.

% java fr.upem.net.tcp.blocking.ServerSumBetter 7777
% java -jar ClientSumChrono.jar localhost 7777
% java fr.upem.net.tcp.blocking.ServerSum 7777
% java -jar ClientSumChrono.jar localhost 7777

Basic chat server ChatInt

The goal of this exercise is to write a simple chat server. We will start from a chat where we only exchange INTs in BigEndian. Later on we will move on to a protocol where we do exchange messages.

ChatInt protocol

The format of the messages that circulate between clients and the servers are simply INT en BigEndian

When a message is received by the server, it retransmits it to all of the connected clients.

Starting from the draft ServerChatInt.java, write a server for the ChatInt protocol in non-blocking mode.

The main difference with regard to the server we have seen so far is that, when a message is received from a client, the server must retransmit it to all other connected clients. In the draft code given, this will be the role of the method serverChatInt.broadcast. This method will iterate over the SelectionKey corresponding to every client and call the method context.queueMessage of the corresponding Context object.
The method context.queueMessage cannot simply write an INT into the output ByteBuffer because it could be full. We will therefore use a Queue<Integer> to keep all of the arriving messages that are to be retransmitted to the corresponding client. It will be the method context.processOut that will have the responsibility of filling the output ByteBuffer by looking at the message queue.

In order to test your server, use the jar ClientChatInt.jar. This client sends the INT given in the command line and prints out the INT received from the server.

% java fr.upem.net.tcp.nonblocking.ServerChatInt 7777
% java -jar ClientChatInt.jar localhost 7777
% java -jar ClientChatInt.jar localhost 7777

When you write down a number on the keyboard in any one of the two clients, you should then see it printed on the screen in both.

Chaton chat server

We now consider a more complex protocol where the clients send messages with their login name.
Protocole Chaton

A protocol message packet is made out of a login and a text in the following format:

+------------------+------------+------------------+------------+
| Login size (INT) | Login UTF8 | Text  size (INT) | Texte UTF8 |
+------------------+------------+------------------+------------+

The packets should not exceed 1024 bytes.

When a message packet is received by the server, it will broadcast it to all of the clients.

With regard to the previous protocol, the added difficulty comes from the fact that we need to discover the message packets contained in ByteBuffer bbin.

In order to do this, we propose an architecture based on the interface Reader.java. The interface Reader is parametrized according to a type T which is the target type to extract from the ByteBuffer

The methods of the interface must have the following behaviour:

For example, we give you IntReader.java implementing the interface Reader. This class extracts INT in BigEndian.

In ServerChatInt, we may then rewrite the method processIn as follows:

private void processIn() {
  for(;;){
   Reader.ProcessStatus status = messageReader.process(bbIn);
   switch (status){
      case DONE:
          Integer value = messageReader.get();
          server.broadcast(value);
          messageReader.reset();
          break;
      case REFILL:
          return;
      case ERROR:
          silentlyClose();
          return;
    }
  }
}  

Write a class StringReader implementing the interface Reader<String> which extracts String in the format:

+------------+------------+
| Size (INT) | Texte UTF8 | 
+------------+------------+  
The maximum size is 1024.

Verify your class with the unit tests StringReaderTest.java

Write a class MessageReader implementing the class Reader<Message> in order to read the message packets of the protocol Chaton.

Write a non-blocking server for the protocol Chaton.

In order to test your server, you may use the client ClientChat.jar.

% java -jar ClientChat.jar Bob localhost 7777