I have implemented a simple client-server solution using Java sockets and useful classes from java.util.concurrent. The communication protocol is rather simple: Client sends a string with the appended request_info#.A server responds to a client with the message that provides a description on how to use a server.If client sends server_time then a server will send back a current server time.If client sends a quit - a server will process a client disconnect.A default case: client sends an arbitrary string then a server simply bounces it back to a client.I have tested my solution by spawning a fixed number of client threads. Each of them sends a command from a txt file to a server. Some technical remarks:A configuration for the client and server (such as port number and host address) is loaded from an .xml file.To start a server: java jar app.jar server config config.xml.To start a client: java jar app.jar client config config.xml.I would like to seek any suggestions on whether I have correctly implemented the following class (serves as an abstraction for a message between client and server):public class Message {    private Socket socket;    private String message;    private static Logger logger = Logger.getLogger(Message.class);    public void setSocket(Socket socket) {        this.socket = socket;    }    public String getMessage() {        return message;    }    public Socket getSocket() {        return socket;    }    public void setStringMessage(String message) {        this.message = message;    }    public void setMessageInputSources(InputStream inputStream) throws IOException {        String s;        BufferedReader bufferRead = new BufferedReader(new InputStreamReader(inputStream));        s = bufferRead.readLine();        this.message = s;    }    public synchronized String getCommand() {        String stringMessage = this.getMessage();        return StringUtils.upperCase(stringMessage.split(#)[0]);    }    public void send(String message) throws IOException{        DataOutputStream dataOutputStream = new DataOutputStream(this.socket.getOutputStream());        dataOutputStream.writeUTF(message);        dataOutputStream.flush();        this.setStringMessage(message);    }    public Message receive() throws IOException {        String data;        DataInputStream dataInputStream = new DataInputStream(this.socket.getInputStream());        data = dataInputStream.readUTF();        this.setStringMessage(data);        return this;    }    @Override    public String toString() {        return this.message;    }}Do I properly manage a case when all client threads are done with their jobs and I shut down an application? Are there any improvements to be made?public class MainTest {    private static final int NUMBER_OF_THREADS = 4;        public static void main(String[] args) throws IOException, InterruptedException {            CountDownLatch countDownLatch = new CountDownLatch(NUMBER_OF_THREADS);            Thread serverThread = new Thread(() -> Server.start(new File(config.xml), countDownLatch));            serverThread.setName(server_thread);            Thread clientThread = new Thread(() -> {                try {                    new Client(new File(config.xml), new FileInputStream(commands.txt)).start(NUMBER_OF_THREADS, countDownLatch);                } catch (ExecutionException | IOException | InterruptedException e) {                    e.printStackTrace();                }            });            clientThread.setName(Running client threads,  + 10);            serverThread.start();            clientThread.start();            if(countDownLatch.getCount() == 0){                System.exit(0);            }        }    }Here is the link to my project: GitHub Repository
Simple TCP client-server solution
java;socket;server;tcp;client