IdUpperCase
protocol and the behavior of the clients ClientIdUpperCaseUDPOneByOne
and ClientIdUpperCaseUDPBurst
.
IdUpperCase
long
id in BigEndian identifying the request/response,
UTF-8
.
The program ClientIdUpperCaseUDPOneByOne
accepts as parameters the input file name (in-filename
), the output file name ( out-filename
), the timeout before resending in milliseconds (timeout
) and the IdUpperCase
server address (hostname
port
). For instance,
$ java fr.uge.net.udp.nonblocking.ClientIdUpperCaseUDPOneByOne in.txt out.txt 300 localhost 7777The client
ClientIdUpperCaseUDPOneByOne
sends one by one the lines found in file in-filename
to the server, and writes the responses in the file out-filename
, both exchanged with respect to the protocol IdUpperCase
.
For instance, if there are two lines in in-filename
, the client sends a request for the first line with id 0. If no response with id 0 is received in timeout
milliseconds, the client re-sends the same request, and again until a response with id 0 is received. Then, the client sends the request for the second line with id 1, and so on.
The major difference is that both sending and receiving operations will be performed in the same thread, using non-blocking IO.
Starting from the code ClientIdUpperCaseUDPOneByOne.java, implement the non-blocking client ClientIdUpperCaseUDPOneByOne
.
selector.select()
is blocking: so, a call to selector.select()
returns only when (at least one) a monitored opertation is detected. For our client, we need to limit the waiting time in selector.select()
to be able to re-send a request when no response is received after timeout
milliseconds.selector.select(int delay)
, which returns after at most delay
milliseconds even if nothing is selected.State state
to store our current state in the protocol.
enum State {SENDING, RECEIVING, FINISHED};Our client is in
SENDING
state if he wants to send a request; if he is in RECEIVING
state then he is waiting for answers and he is in state FINISHED
when he received the response of the last line request.
Thus, we have slightly modified the selection loop:
while (!isFinished()) { try { selector.select(this::treatKey,updateInterestOps()); } catch(UncheckedIOException tunneled) { throw tunneled.getCause(); } } dc.close();Since our selector only monitors a single
DatagramChannel
, there is only one key to consider, which we store in the field uniqueKey
of the client class.
We assume that only the updateInterestOps()
method is allowed to change the interestOps
value of this uniqueKey
. Furthermore, this updateInterestOps()
method returns the maximum amount of time we can wait in selector.select()
.selector.select(0)
is equivalent to selector.select()
, which may wait indefinitely.
We provide you with a server ServerIdUpperCase.jar and you could use the UDP proxy UDPProxy.jar that simulates losses and delays in exchanges.
$ java -jar ServerIdUpperCaseUDP.jar 4545 UTF-8 $ java -jar UDPProxy.jar 7777 localhost 4545 -no-swap
Test your code with file in.txt as follows:
$ java fr.uge.net.udp.nonblocking.ClientIdUpperCaseUDPOneByOne in.txt out.txt 300 localhost 7777
Do not forget to use the proxy...
Check that your client does not re-send its request too early, that is before waiting timeout
milliseconds since its last attempt... This could be the case when receiving a response to another request (with an unexpected ID) if your client immediately re-sends the request without checking the time elapsed sine last sending.
To identify such a situation, we provide you with a fake server ServerIdUpperCaseTestTimeout.jar. Instead of normaly answering to a received request (by sending the uppercase string), this fake server arbitrarily answers to the client, every 100 milliseconds, a fake response with an id -1 ; it also prints the time elpased between all received packets.
You shoud test with:
$ java -jar ServerIdUpperCaseUDPTestTimeout.jar 4545 $ java fr.uge.net.udp.nonblocking.ClientIdUpperCaseUDPOneByOne in.txt out.txt 300 localhost 4545And if your client is correct the server should print times close to the timeout.
Time since last receive: 301 ms Time since last receive: 301 ms Time since last receive: 301 ms Time since last receive: 301 ms Time since last receive: 300 ms Time since last receive: 301 ms ....
Starting from the same draft of code ClientIdUpperCaseUDPOneByOne.java,
you now have to implement a client ClientIdUpperCaseUDPBurst
that sends burst of requests.
You shoud test with file in.txt as follows:
$ java -jar ServerIdUpperCaseUDP.jar 4545 UTF-8 $ java -jar UDPProxy.jar 7777 localhost 4545 -no-swap $ java fr.uge.net.udp.nonblocking.ClientIdUpperCaseUDPBurst in.txt out.txt 300 localhost 7777
You are only allowed to perform one send call in the doWrite
method. For each send operation, you have to ask for the permission of the selector.