#java #sockets #networking
Вопрос:
Я пытаюсь реализовать систему однорангового чата с использованием java для выполнения некоторых университетских домашних заданий. Каждый узел состоит из сервера и клиента.Сервер получает сообщение, а клиент отправляет сообщения. Когда вы устанавливаете новый порт для своего узла, вызывается следующая функция :
private void setServer(int port) {
try {
serverSocket = new ServerSocket(port);
new Thread(() -> {
while (!serverSocket.isClosed()) {
try {
Socket socket = serverSocket.accept();
addNumberOfConnections(1);
startNewConnection(socket);
addNumberOfConnections(-1);
} catch (IOException ignored) {}
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
}
Где numberOfConnections-это некоторая переменная, которая задана для сохранения количества людей, отправивших сообщение, но оно не было должным образом получено сервером. и функция добавления реализована синхронизировано следующим образом:
public synchronized void addNumberOfConnections(int num) {
numberOfConnections = num;
}
И начать новое соединение-это функция, которая выглядит следующим образом :
public void startNewConnection(Socket socket) {
try {
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
String message = dataInputStream.readUTF();
addMessage(message);
dataInputStream.close();
socket.close();
System.err.println(messages.size());
} catch (IOException e) {
e.printStackTrace();
}
}
и функция добавления сообщений также реализована синхронизировано следующим образом :
private synchronized void addMessage(String message) {
messages.add(message);
senders.add(Utils.ExtractMessage(message).getKey());
}
Я использую количество подключений, чтобы все сообщения полностью приземлялись перед чтением любых данных, используя следующую функцию :
private void waitUntilEnds() {
while (numberOfConnections != 0) {
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Finally I send a message using the following function :
private void globalMessage(String message, String host, int port) {
try {
Socket socket = new Socket(host, port);
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
Utils.sendMessage(dataOutputStream, Utils.putInNetworkFormat(message, Main.getUser()));
dataOutputStream.close();
socket.close();
System.out.println("success");
} catch (IOException | IllegalArgumentException e) {
System.out.println("could not send message");
}
}
Проблема в том, что, хотя я использую протокол TCP, иногда я получаю не все сообщения. И что еще более удивительно, некоторое время я получаю все сообщения, но не могу прочитать их все, кроме вызова функции waitUntil в начале. Более конкретно, я пытаюсь предоставить следующую информацию(тестовый пример) для моей программы :
userconfig --create --username bean --password qwerty123trewq
userconfig --login --username bean --password qwerty123trewq
portconfig --listen --port 17091
focus --start --host 127.0.0.1
send --message "This is it" --port 17091 --host 127.0.0.1
send --message "It just works" --port 17091
portconfig --listen --port 17097 --rebind
focus --port 17097
send --message "I'm calling thou"
focus --stop
send --message "General Kenobi!" --port 17097
send --message "Are you there?" --port 17097 --host 127.0.0.1
portconfig --close --port 17097
show --count --messages
show --messages
show --count --senders
portconfig --listen --port 17071
focus --start --host 127.0.0.1 --port 17071
send --message "Okay I'm back"
send --message "Are you still there?" --port 17071 --host 127.0.0.1
send --message "Ight imma head out, bye!" --port 17071
show --messages
show --senders
фокус-это ничто, но когда вы это сделаете, это будет хост или порт узла по умолчанию, на который вы хотите отправить свое сообщение.
предоставляя программе этот ввод несколько раз примерно один раз каждые 5 раз, она получает все сообщения, но не показывает их все, и один раз каждые 10 раз она не получает сообщения, которые отправляются после повторной привязки. Я думаю, что я синхронизировал все, что было необходимо ( ошибка не может быть в логике, так как в большинстве случаев она выдает правильный вывод). И идеи по поводу того, что происходит?
Изменить: вот репозиторий программы на github. Я использую аннотации для анализа команд, основная логика которых находится в классах Сервер, Клиент и Отправка сообщения;
Комментарии:
1. Как сказал Кельвин Шуфс, я думаю, вам следует использовать класс Thread. Создавайте потоки для каждого процесса.
Ответ №1:
Одна небольшая проблема, которая сразу же возникает, заключается в том, что, когда ваш сервер принимает сокет, он не создает для него новый поток. В этом случае, поскольку обработка сокета выполняется быстро, это не слишком важно. Это означает, что вы numberOfConnections
никогда не пройдете 1, хотя.
Причина, по которой ваша команда может не отображать сообщения, заключается в кэшировании процессора/виртуальной машины, что может привести к многопоточности. Поток вашего сервера изменил messages
поле, но ваша команда выполняется в другом потоке, который видит старую кэшированную версию списка.
В противном случае неясно, перечисляются ли команды в вашем тестовом примере с ошибками, ожидает ли процесс завершения,…
Комментарии:
1. Я согласен-ваше чтение «сообщений» в startNewConnection должно быть синхронизировано