Вопрос по предыдущей задаче (Чат (8)). Решение уже прошло валидацию, поэтому не могу прикрепить код к той задаче.
Ниже - условие этой задачи. У меня вопрос по этому методу: String serverHandshake(Connection connection)
39 строка - мы проверяем соответствие сообщения клиента типу USER_NAME.
А где описание этого типа? Не совсем понимаю....
33 строка - Message messageOut = new Message(MessageType.NAME_REQUEST);
А где само сообщение? Решение я по большей части списала и не понимаю, как это работает.
УСЛОВИЕ
Класс Handler должен реализовывать протокол общения с клиентом.
Выделим из протокола отдельные этапы и реализуем их с помощью отдельных методов:
Этап первый - это этап рукопожатия (знакомства сервера с клиентом).
Реализуем его с помощью приватного метода String serverHandshake(Connection connection) throws IOException, ClassNotFoundException .
Метод в качестве параметра принимает соединение connection, а возвращает имя нового клиента.
Реализация метода должна:
1) Сформировать и отправить команду запроса имени пользователя
2) Получить ответ клиента
3) Проверить, что получена команда с именем пользователя
4) Достать из ответа имя, проверить, что оно не пустое и пользователь с таким именем еще не подключен (используй connectionMap)
5) Добавить нового пользователя и соединение с ним в connectionMap
6) Отправить клиенту команду информирующую, что его имя принято
7) Если какая-то проверка не прошла, заново запросить имя клиента
8) Вернуть принятое имя в качестве возвращаемого значения
Требования:
• В классе Handler должен присутствовать метод private String serverHandshake(Connection connection).
• Метод serverHandshake должен отправлять запрос имени используя метод send класса Connection.
• До тех пор, пока тип сообщения полученного в ответ не будет равен MessageType.USER_NAME, запрос имени должен быть выполнен снова.
• В случае, если в ответ пришло пустое имя, запрос имени должен быть выполнен снова.
• В случае, если имя уже содержится в connectionMap, запрос имени должен быть выполнен снова.
• После успешного проведения всех проверок, метод serverHandshake должен добавлять новую пару (имя, соединение) в connectionMap и отправлять сообщение о том, что имя было принято.
• Метод serverHandshake должен возвращать имя нового клиента с которым было установлено соединение.
package com.javarush.task.task30.task3008;
import java.io.IOException;
import java.net.Socket;
import java.net.ServerSocket;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.javarush.task.task30.task3008.MessageType.NAME_REQUEST;
public class Server {
private static Map<String, Connection> connectionMap = new ConcurrentHashMap<String, Connection>();
public static void sendBroadcastMessage(Message message) {
for (Connection connection : connectionMap.values()) {
try {
connection.send(message);
} catch (IOException e) {
ConsoleHelper.writeMessage("Не удалось отправить сообщение " + connection.getRemoteSocketAddress());
}
}
}
private static class Handler extends Thread {
private Socket socket;
public Handler(Socket socket) {
this.socket = socket;
}
private String serverHandshake(Connection connection) throws IOException, ClassNotFoundException {
Message messageOut = new Message(MessageType.NAME_REQUEST);
Message messageIn;
String name = "";
while (true){
connection.send(messageOut);
messageIn = connection.receive();
if(messageIn.getType() != MessageType.USER_NAME){
continue;
}
name = messageIn.getData();
if(name.isEmpty() || connectionMap.containsKey(name)){
continue;
}
connectionMap.put(name,connection);
connection.send(new Message(MessageType.NAME_ACCEPTED));
return name;
}
}
}
public static void main(String[] args) throws Exception {
ConsoleHelper.writeMessage("Введите порт сервера:");
int port = ConsoleHelper.readInt();
try (ServerSocket serverSocket = new ServerSocket(port)) {
ConsoleHelper.writeMessage("Чат сервер запущен.");
while (true) {
Socket socket = serverSocket.accept();
new Handler(socket).start();
}
} catch (Exception e) {
ConsoleHelper.writeMessage("Произошла ошибка при запуске или работе сервера.");
}
}
}
NAME_REQUEST. Клиент должен ответить сообщением типаUSER_NAMEсодержащее непустое поле данных. Данные в ответном сообщении клиента, в соответствие с типом сообщения (USER_NAME) считаются именем пользователя. Типы сообщений, являются константами перечисленияMessageType. Каждое сообщение (классMessage), кроме обязательного типа сообщения, может содержать ещё опциональное поле данных типаString. Об этом нам говорит наличие двух конструкторов классаMessage, один из которох, в качестве аргумента, принимает только значение типаMessageType, а другой - значения типовMessageTypeиString. Поскольку сервер, в строке 37, посылает клиенту запрос имени, а это отдельный тип сообщений, то клиент может распознать что от него хотят только по типу сообщения. Поэтому, при формировании запроса в строке 33, сервер оставляет опциональное поле данных пустым. В 39 строке, сервер просто запрашивает тип ответа, пришедшего от клиента и сравнивает с тем что должно быть. Напомню ещё раз что типы сообщений являются константами перечисленияMessageType. Это перечисление есть у Вас в дереве классов, и лежит в том же пакете, что и все остальные классы, т.е. в пакетеcom.javarush.task.task30.task3008. P.S. При списывании рекомендую хотя бы разобраться в том, что списываете.