Why does client not receive final server answer in non-blocking client-server app?

109 Views Asked by At

I am trying to figure out NIO in Java doing some simple client-server project.

The case is I have to concurrent clients in cached thread pool executor, who are communicating with single-threaded server using non-blocking NIO channels.

The problem is that last client cannot receive last server's sent message. It locks in infinite loop waiting for upcoming data.

ClientTask class:

public class ClientTask extends FutureTask<String> {

    private Client client;
    private List<String> reqList;   // requests list (without last and first)
    private boolean showRes;        // print request results

    public ClientTask(Client client, List<String> reqList, boolean showRes) {
        super(() -> ClientTask.getLogWhenArrives(client, reqList, showRes));
        this.client = client;
        this.reqList = reqList;
        this.showRes = showRes;
    }

    public static ClientTask create(Client c, List<String> reqList, boolean showRes) {
        return new ClientTask(c, reqList, showRes);
    }

    private static String getLogWhenArrives(Client client, List<String> reqList, boolean showRes) {
        client.connect();
        String response = client.send("login " + client.getId());
        if (showRes) System.out.println(response);

        for (String req : reqList) {
            response = client.send(req);
            if (showRes) System.out.println(response);
        }

        String responseLog = client.send("bye and log transfer");

        client.close();
        return responseLog;
    }
}

Client send():

    public String send(String req) {
        ByteBuffer reqBuffer = ByteBuffer.wrap((req + END).getBytes());
        try {
            channel.write(reqBuffer);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return receive();
    }

Client receive()

 public String receive() {
        StringBuilder result = new StringBuilder();
        try {
            inBuff.clear();
            readLoop:
            while (true) { // THIS LOOP WON'T END
                int n = channel.read(inBuff);

                if (n == -1) {
                    break;
                }
                if (n > 0) {
                    inBuff.flip();
                    CharBuffer cb = charset.decode(inBuff);

                    while (cb.hasRemaining()) {
                        char c = cb.get();
                        if (c == END.charAt(0)) {
                            break readLoop;
                        }
                        result.append(c);
                    }
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        return result.toString();
    }

Main:

public class Main {

  public static void main(String[] args) throws Exception {
    String fileName = System.getProperty("user.home") + "/PassTimeServerOptions.yaml";
    Options opts = Tools.createOptionsFromYaml(fileName);
    String host = opts.getHost();
    int port = opts.getPort();
    boolean concur =  opts.isConcurMode();
    boolean showRes = opts.isShowSendRes();
    Map<String, List<String>> clRequests = opts.getClientsMap();
    ExecutorService es = Executors.newCachedThreadPool();
    List<ClientTask> ctasks = new ArrayList<>();
    List<String> clogs = new ArrayList<>(); 

    Server s = new Server(host, port);
    s.startServer();

    // start clients
    clRequests.forEach( (id, reqList) -> {
      Client c = new Client(host, port, id);
      if (concur) {
        ClientTask ctask = ClientTask.create(c, reqList, showRes);
        ctasks.add(ctask);
        es.execute(ctask);
      }
    });

    if (concur) {
      ctasks.forEach( task -> {
        try {
          String log = task.get();
          clogs.add(log);
        } catch (InterruptedException | ExecutionException exc) {
          System.out.println(exc);
        }
      });
      clogs.forEach( System.out::println);
      es.shutdown();
    }
    s.stopServer();
    System.out.println("\n=== Server log ===");
    System.out.println(s.getServerLog());
  }

}

Server is sending all the info and channels are open and connected.

0

There are 0 best solutions below