Даже не знаю как корректно описать проблему. Вообщем сделал класс Commander, который использует и сервер, и клиент. Его роль в том, чтобы абстрагировать методы отправки и получения данных клиента/сервера. Создалась следующая проблема: клиент вызывает несколько методов этого класса, все работает корректно, но при повторном вызове клиент зависает. Понимаю, что решение кроется в правильном создании потоков ввода вывода, но для начала хочу хотя бы понять в чем же дело, прежде чем начать править.
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();
}
}
}
Пробовал вынести все потоки ввода/вывода в private поля, и в конструкторе присваивать им необходимые ссылки, но стало еще хуже.
До этого также была проблема: программа выполняла одну команду и сокет закрывался, после чего вылетала ошибка. Решилось, когда прочитал, что при открытии потока через try-with-resource (а на тот момент так и было), сокет закрывается вместе с потоком.
*Правка: Добавил код серверной части. Этот обработчик запускается через ExecutorService, при новом подключении.
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);
}
}
Вообщем, решение оказалось элементарным. Я банально забыл зациклить принятие команд сервером в методе
@Override
public void run() {
try {
while (true) {
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();
}
}
Оборудование для ресторана: новинки профессиональной кухонной техники
Частный дом престарелых в Киеве: комфорт, забота и профессиональный уход
Всем приветВот пишу отдельный класс java, который будет отвечать чисто только за управление Bluetooth на android-устройстве
Приложение работает, но принято ли так писать в Java? Просто для каждой переменной неудобно писать "public static String
Извините за глупый вопрос, но обязательно ли в качестве аргумента setPreferredSize использовать объект Dimension?
Не могу найти класс InlineKeyboardMarkup в библиотеке TELEGRAM API telegrambots-41-jar-with-dependencies