Я создаю настольное приложение с javaFX. В этом приложении я должен проверить новые запросы от других клиентов к текущему пользователю; если текущий пользователь (получатель) и другой удаленный клиент (отправитель) активны, используя сокеты.
(в конце указывается сомнение)
Я постараюсь чтобы все было как можно проще.
Существует четыре класса, связанных с реализацией сокетов:
Сервер
ClientHandler
Клиент
ServerConnection
1) Сервер
public class Server {
private static final int PORT = 9090;
private static HashMap<String,ClientHandler> clients = new HashMap<>();
private static ExecutorService pool = Executors.newFixedThreadPool(4);
public static void main(String[] args) throws IOException {
ServerSocket listener = new ServerSocket(PORT);
BufferedReader in;
while (true) {
System.out.println("server is waiting for client to connect");
Socket client = listener.accept();
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
String id = in.readLine();
System.out.println(id);
ClientHandler clientThread = new ClientHandler(client,clients,id);
clients.put(id,clientThread);
pool.execute(clientThread);
}
}
}
2) ClientHandler
public ClientHandler(Socket clientSocket, HashMap<String, ClientHandler> clients, String id) throws IOException {
this.id = id;
this.client = clientSocket;
this.clients = clients;
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
out = new PrintWriter(client.getOutputStream(), true);
}
@Override
public void run() {
try {
while (true) {
String request = in.readLine();
System.out.println(request);
if(request.startsWith("say")){
outToAll(request);
}
}
} catch (Exception e) {
System.out.println(e);
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
out.close();
}
}
//this method is used to send message to all the active clients
public void outToAll(String msg){
clients.forEach((key,client)->{
c.out.println(msg);
});
}
3) Клиент
public Client(String id) throws IOException {
this.id = id;
this.socket = new Socket(IP_ADDRESS, PORT);
this.serverConnection = new ServerConnection(socket);
this.keyboard = new BufferedReader(new InputStreamReader(System.in));
this.out = new PrintWriter(socket.getOutputStream(), true);
}
@Override
public void run() {
new Thread(serverConnection).start();
try {
out.println(id);
while (true) {
String command = keyboard.readLine();
if (command.equals("quit")) break;
out.println(command);
}
} catch (Exception e) {
System.out.println(e);
}
out.close();
try {
socket.close();
keyboard.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void stopSocket() throws IOException {
socket.close();
}
4) ServerConnection
//Server connection is connection from client side to the server.which reads message from server and just prints into the console
public ServerConnection(Socket server) throws IOException {
this.server = server;
this.in = new BufferedReader(new InputStreamReader(this.server.getInputStream()));
}
@Override
public void run() {
try{
while (true){
String msg = in.readLine();
if(msg == null) break;
System.out.println("Server says > "+ msg);
}
}catch (Exception e){
System.out.println(e);
}finally {
}
}
Итак, это мои классы, связанные с сервисом сокетов.
Поскольку я использую javaFX, каждый класс Client Runnable должен запускаться в своем собственном потоке, поэтому для достижения этой цели я создал поток рядом с моим контроллером javaFX с именем HomeController
, который вызывается всякий раз, когда клиент входит в систему. Затем HomeController создает клиентскую ветку, как показано ниже
Я надеюсь, что это исправит Это можно сделать, так как мне нужен другой поток, чтобы клиент
не блокировал поток пользовательского интерфейса javafx
//as I have access to the `id` and already have created a Client object
// I hope that this the correct way to do so
this.client = new Client(id);
new Thread(client).start();
И всякий раз, когда клиент Выйдя из системы, я закрываю клиентский сокет как
//above created client
client.stopSocket();
Таким образом, таким образом я создал отдельный поток клиента для каждого клиента, подключенного к серверу.
Сомнение
Я запускаю несколько экземпляров приложения javafx и захожу с разными идентификаторами пользователей.
Итак, в соответствии с реализацией, когда я что-то наберу в клиентской консоли, это должно быть напечатано в каждом и каждая консоль других клиентов тоже. Но это не происходит все время. некоторые клиенты получают сообщение, а некоторые нет, а иногда никто не получает сообщение. Я предполагаю, что некоторые клиенты заблокированы, и я не могу понять.
Поэтому для целей тестирования я создал другой проект с теми же 4 классами и вместо определения класса Client
как выполняемого, я создал в нем основной метод , И запустил несколько экземпляров класса Client. Сохраняя покой вещи такими же. Эта реализация прекрасно работает без каких-либо недостатков.
Пожалуйста, помогите мне через это, я уже 4 дня сталкиваюсь с этой проблемой.