I do not even know how to correctly describe the problem. In general, I made the Commander class, which uses both the server and the client. Its role is to abstract methods of sending and receiving client / server data. The following problem was created: the client calls several methods of this class, everything works correctly, but when it is called again, the client hangs. I understand that the solution lies in the correct creation of input-output streams, but first I want to at least understand what the matter is before I begin to edit.
import java.io.*; import java.net.Socket; public class Commander { private Socket socket; public Commander(Socket socket) { this.socket = socket; } private void sendObject(Serializable object) throws DisconnectException { try { ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); out.writeObject(object); out.flush(); } catch (IOException e) { throw new DisconnectException(); } } private Object receiveObject() throws DisconnectException { Object object = null; try { ObjectInputStream in = new ObjectInputStream(socket.getInputStream()); object = in.readObject(); } catch (IOException e) { throw new DisconnectException(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return object; } public void sendCommand(ServerCommand command) throws DisconnectException { sendObject(command); } public ServerCommand receiveCommand() throws DisconnectException { return (ServerCommand) receiveObject(); } public void sendAccount(Account account) throws DisconnectException { sendObject(account); } public Account receiveAccount() throws DisconnectException { return (Account) receiveObject(); } public void sendAccountID(int id) throws DisconnectException { try { DataOutputStream out = new DataOutputStream(socket.getOutputStream()); out.writeInt(id); out.flush(); } catch (IOException e) { throw new DisconnectException(); } } public int receiveAccountID() throws DisconnectException { try { DataInputStream in = new DataInputStream(socket.getInputStream()); int id = in.readInt(); return id; } catch (IOException e) { throw new DisconnectException(); } } public void sendAnswer(boolean answer) throws DisconnectException { try { DataOutputStream out = new DataOutputStream(socket.getOutputStream()); out.writeBoolean(answer); out.flush(); } catch (IOException e) { throw new DisconnectException(); } } public boolean receiveAnswer() throws DisconnectException { try { DataInputStream in = new DataInputStream(socket.getInputStream()); boolean answer = in.readBoolean(); return answer; } catch (IOException e) { throw new DisconnectException(); } } public void closeSocket() { try { if (socket != null) { socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } I tried to put all I / O streams into private fields, and in the constructor assign them the necessary links, but it got worse.
Before that, there was also a problem: the program executed one command and the socket was closed, after which an error occurred. It was decided when I read that when opening a stream through try-with-resource (and at that time it was), the socket closes with the stream.
* Edit: Added server side code. This handler is launched via the ExecutorService, with a new connection.
import java.net.Socket; public class ClientHandler implements Runnable { private Socket socket; private Commander commander; public ClientHandler(Socket socket) { this.socket = socket; this.commander = new Commander(socket); } @Override public void run() { try { ServerCommand command = commander.receiveCommand(); switch (command) { case LOGIN: login(); break; case CREATE_ACCOUNT: createAccount(); break; } } catch (DisconnectException e) { System.out.println(socket.getRemoteSocketAddress().toString() + " was disconnected."); commander.closeSocket(); } } private void login() throws DisconnectException { int id = commander.receiveAccountID(); boolean answer = isAccountExist(id); commander.sendAnswer(answer); if (answer) { commander.sendAccount(Server.getAccounts().get(id)); } } private void createAccount() throws DisconnectException { Account account = commander.receiveAccount(); int id = account.hashCode(); boolean answer = !isAccountExist(id); commander.sendAnswer(answer); if (answer) { Server.getAccounts().put(id, account); } } private boolean isAccountExist(int id) { return Server.getAccounts().keySet().contains(id); } }