Java network programming – Why do I need a framework instead of raw socket

Please, could you help me to understand the value brought by a network framework (such as Netty or other frameworks for network programming) ?

So far, to exchange data between 2 services, I use raw sockets and I am pretty happy with it. Here are example of Server and Client code. The Server use a ThreadPoolExecutor to handle requests in parallel. The client try to oppress the server by sending request in parallel.

Server :

public class Server {

    private final static Logger logger = LogManager.getLogger();

    private static ServerSocket serverSocket;

    public static void main(String[] args) throws IOException {
        int portNumber = ArgUtils.getArgIntegerValue(args, "port", 8090);
        // Build the pool of threads to handle requests
        BasicThreadFactory factory = new BasicThreadFactory.Builder().namingPattern("RequestHandlerThread-%d").build();
        ThreadPoolExecutor es = new ThreadPoolExecutor(50, 50, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<>(500), factory);
        es.allowCoreThreadTimeOut(true);
        try {
            serverSocket = new ServerSocket(portNumber);
            logger.debug("Application started - Wait for connections on port {}", portNumber);
            while (true) {
                Socket clientSocket = serverSocket.accept();
                es.execute(() -> doWithSocket(clientSocket));
            }
        } catch (Exception e) {
            logger.fatal("Application finish", e);
        } finally {
            logger.debug("Shutting down application");
            serverSocket.close();
            es.shutdownNow();
        }
    }

    private static void doWithSocket(Socket socket) {
        try (DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
             DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()))) {
            String action = dis.readUTF();
            // Send a message x times
            if ("message".equals(action)) {
                int x = dis.readInt();
                for (int i = 0; i < x; i++) {
                    dos.writeUTF("message " + i);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

Client :

public class Client {

    private final static Logger logger = LogManager.getLogger();

    private static String host;

    private static int port;

    public static void main(String[] args) throws IOException, InterruptedException {
        long t0 = currentTimeMillis();
        host = ArgUtils.getArgValue(args, "host", "localhost");
        port = ArgUtils.getArgIntegerValue(args, "port", 8090);

        ExecutorService es = Executors.newFixedThreadPool(10);
        ExecutorCompletionService<Object> cs = new ExecutorCompletionService<>(es);
        int n = 20;
        for (int i = 0; i < n; i++) {
            int finalI = i;
            cs.submit(() -> {
                performExchange(finalI);
                return null;
            });
        }
        es.shutdown();
        for (int i = 0; i < n; i++) {
            try {
                cs.take().get();
            } catch (ExecutionException e) {
                throw new RuntimeException("Execution of a subtask failed", e);
            }
        }
        long t1 = currentTimeMillis();
        logger.debug("duration : {} ms", t1 - t0);
    }

    private static void performExchange(int t) throws IOException {
        Socket socket = new Socket(host, port);
        try (DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
             DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()))) {
            dos.writeUTF("message");
            int x = 100;
            dos.writeInt(x);
            dos.flush();
            try {
                while (true) {
                    String response = dis.readUTF();
                    int y = Integer.valueOf(response.substring(response.indexOf(" ") + 1));
                    if (y == 0 || y == x - 1) {
                        logger.debug("Task {} : {}", t, response);
                    }
                }
            } catch (EOFException e) {
                // Fail silently
            }
        }
    }

}

It works quite well. What a network programming framework would improve ?

Thank you