本文介紹了如何將對象從inputStream客戶端返回到JavaFX控制器?的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!
問題描述
所以基本上我有一個MainConstroll類,它有每個按鈕的方法。我還有一個服務器多客戶端應用程序。在客戶端,我有一個sendMessage方法,它將一個字符串和一個對象作為參數發送到outputStreams到服務器。
在相同的方法中,我有兩個來自服務器的消息的inputStream和一個對象。問題是此方法運行在實現Run方法的Thread上,而我無法返回該對象。
我嘗試創建一個靜態類來保存這些參數,但在控制器類中調用時,getter為空。
實現此目標的最佳方法是什么?
public void onSaveButton(javafx.event.ActionEvent actionEvent) throws Exception {
Parent root = null;
Boolean type = false;
String message = null;
if (adminCheckbox.isSelected()) {
root = FXMLLoader.load(getClass().getResource("/fxml/admin.fxml"));
type = true;
message = "Admin";
}
if (competitorCheckbox.isSelected()) {
root = FXMLLoader.load(getClass().getResource("/fxml/competitor.fxml"));
message = "Competitor";
}
PersonEntity personEntity = new PersonEntity();
personEntity.setIdTeam(Integer.parseInt(teamField.getText()));
personEntity.setType(type);
personEntity.setUsername(usernameField.getText());
client.sendMessageToServer(message, personEntity);
System.out.println(Utils.getMessage());}
和客戶端方法:
public void sendMessageToServer(String message, Object object) throws Exception {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Say something and the message will be sent to the server: ");
//For receiving and sending data
boolean isClose = false;
while (!isClose) {
try {
ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
if (message.equals("Bye")) {
isClose = true;
}
outputStream.writeObject(message);
outputStream.writeObject(object);
String messageFromServer = (String) inputStream.readObject();
//System.out.println(messageFromServer);
int index = messageFromServer.indexOf(' ');
String word = messageFromServer.substring(0, index);
if (messageFromServer.equals("Bye")) {
isClose = true;
}
if (!word.equals("LIST")) {
Object obj = (Object) inputStream.readObject();
Utils.setMessage(messageFromServer);
return;
//Utils.setObject(obj);
//System.out.println("IN FOR " + Utils.getMessage());
} else {
List<Object> list = (List<Object>) inputStream.readObject();
Utils.setMessage(messageFromServer);
Utils.setObjects(list);
return;
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
推薦答案
我不知道您的服務器是什么,也不知道您的應用程序的其余部分。我知道您正在使用原始的TCP套接字使用自定義協議進行通信。
我所做的是從Java教程中獲取類似示例的代碼。該代碼是來自Writing the Server Side of a Socket的Knock客戶端服務器代碼。基本的服務器代碼沒有改變,我只是用一個JavaFX用戶界面替換了基于控制臺的客戶端。
未更改的服務器代碼:
https://docs.oracle.com/javase/tutorial/networking/sockets/examples/KnockKnockProtocol.java
https://docs.oracle.com/javase/tutorial/networking/sockets/examples/KKMultiServer.java
https://docs.oracle.com/javase/tutorial/networking/sockets/examples/KKMultiServerThread.java
已更換控制臺客戶端:
https://docs.oracle.com/javase/tutorial/networking/sockets/examples/KnockKnockClient.java
我提供了兩種不同的客戶端實現;一種是在JavaFX應用程序線程上進行同步客戶端調用,另一種是使用JavaFX任務進行異步客戶端調用。
當前的基于任務的異步解決方案對于一個完整規模的生產系統來說不夠健壯,因為它在技術上有可能丟失消息,并且它不能可靠地匹配請求和響應消息。但對于這樣的演示來說,這是可以的。
為了簡單執行,UI應用程序在運行時都會在預定義的端口上啟動本地服務器,但您可以刪除代碼以從UI應用程序啟動服務器,并在需要時從命令行運行服務器。
Knock Knock SyncClient.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class KnockKnockSyncClient {
private Socket socket;
private PrintWriter out;
private BufferedReader in;
public String connect(String host, int port) {
try {
socket = new Socket(host, port);
out = new PrintWriter(
socket.getOutputStream(),
true
);
in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()
)
);
return in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public String sendMessage(String request) {
String response = null;
try {
out.println(request);
response = in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
public void disconnect() {
try {
if (socket != null) {
socket.close();
socket = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Knock Knock SyncApp
import javafx.animation.FadeTransition;
import javafx.application.*;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class KnockKnockSyncApp extends Application {
private static final String HOST = "localhost";
private static final int PORT = 8809;
public static final String QUIT_RESPONSE = "Bye.";
private ExecutorService serverExecutor;
private KnockKnockSyncClient client;
private static final String CSS = """
data:text/css,
.root {
-fx-font-size: 20;
}
.list-cell {
-fx-alignment: baseline-right;
-fx-text-fill: purple;
}
.list-cell:odd {
-fx-alignment: baseline-left;
-fx-text-fill: darkgreen;
}
""";
@Override
public void init() {
serverExecutor = Executors.newSingleThreadExecutor(r -> new Thread(r, "KKServer"));
serverExecutor.submit(
() -> {
try {
KKMultiServer.main(new String[]{ PORT + "" });
} catch (Exception e) {
e.printStackTrace();
}
}
);
client = new KnockKnockSyncClient();
}
@Override
public void start(Stage stage) {
ListView<String> messageView = new ListView<>();
TextField inputField = new TextField();
inputField.setPromptText("Enter a message for the server.");
inputField.setOnAction(event -> {
String request = inputField.getText();
messageView.getItems().add(request);
String response = client.sendMessage(request);
messageView.getItems().add(response);
messageView.scrollTo(Math.max(0, messageView.getItems().size() - 1));
inputField.clear();
if (QUIT_RESPONSE.equals(response)) {
closeApp(inputField.getScene());
}
});
VBox layout = new VBox(10,
messageView,
inputField
);
layout.setPadding(new Insets(10));
layout.setPrefWidth(600);
Scene scene = new Scene(layout);
scene.getStylesheets().add(CSS);
stage.setScene(scene);
stage.show();
inputField.requestFocus();
String connectResponse = client.connect(HOST, PORT);
if (connectResponse != null) {
messageView.getItems().add(connectResponse);
}
}
private void closeApp(Scene scene) {
Parent root = scene.getRoot();
root.setDisable(true);
FadeTransition fade = new FadeTransition(Duration.seconds(1), root);
fade.setToValue(0);
fade.setOnFinished(e -> Platform.exit());
fade.play();
}
@Override
public void stop() {
client.disconnect();
serverExecutor.shutdown();
}
public static void main(String[] args) {
launch();
}
}
Knock Knock AsyncClient.java
import javafx.concurrent.Task;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
public class KnockKnockAsyncClient extends Task<Void> {
private final String host;
private final int port;
private final BlockingQueue<String> messageQueue = new LinkedBlockingDeque<>();
public KnockKnockAsyncClient(String host, int port) {
this.host = host;
this.port = port;
}
@Override
protected Void call() {
try (
Socket kkSocket = new Socket(host, port);
PrintWriter out = new PrintWriter(kkSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(kkSocket.getInputStream()));
) {
String fromServer;
String fromUser;
while ((fromServer = in.readLine()) != null) {
// this is not a completely robust implementation because updateMessage
// can coalesce responses and there is no matching in send message calls
// to responses. A more robust implementation may allow matching of
// requests and responses, perhaps via a message id. It could also
// replace the updateMessage call with storage of results in a collection
// (e.g. an observable list) with thread safe notifications of response
// arrivals, e.g. through CompleteableFutures and/or Platform.runLater calls.
updateMessage(fromServer);
System.out.println("Server: " + fromServer);
if (fromServer.equals("Bye."))
break;
fromUser = messageQueue.take();
System.out.println("Client: " + fromUser);
out.println(fromUser);
}
} catch (InterruptedException e) {
if (isCancelled()) {
updateMessage("Cancelled");
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public void sendMessage(String request) {
messageQueue.add(request);
}
}
Knock Knock AsyncApp.java
import javafx.animation.FadeTransition;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
public class KnockKnockAsyncApp extends Application {
private static final String HOST = "localhost";
private static final int PORT = 8809;
public static final String QUIT_RESPONSE = "Bye.";
private ExecutorService serverExecutor;
private ExecutorService clientExecutor;
private static final String CSS = """
data:text/css,
.root {
-fx-font-size: 20;
}
.list-cell {
-fx-alignment: baseline-right;
-fx-text-fill: purple;
}
.list-cell:odd {
-fx-alignment: baseline-left;
-fx-text-fill: darkgreen;
}
""";
@Override
public void init() {
serverExecutor = Executors.newSingleThreadExecutor(r -> new Thread(r, "KKServer"));
serverExecutor.submit(
() -> {
try {
KKMultiServer.main(new String[]{ PORT + "" });
} catch (Exception e) {
e.printStackTrace();
}
}
);
clientExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {
final AtomicInteger threadNum = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
return new Thread(r,"KKClient-" + threadNum.getAndAdd(1));
}
});
}
@Override
public void start(Stage stage) {
ListView<String> messageView = new ListView<>();
KnockKnockAsyncClient client = new KnockKnockAsyncClient(HOST, PORT);
// monitor and action responses from the server.
client.messageProperty().addListener((observable, oldValue, response) -> {
if (response != null) {
logMessage(messageView, response);
}
if (QUIT_RESPONSE.equals(response)) {
closeApp(messageView.getScene());
}
});
TextField inputField = new TextField();
inputField.setPromptText("Enter a message for the server.");
inputField.setOnAction(event -> {
String request = inputField.getText();
logMessage(messageView, request);
client.sendMessage(request);
inputField.clear();
});
VBox layout = new VBox(10,
messageView,
inputField
);
layout.setPadding(new Insets(10));
layout.setPrefWidth(600);
Scene scene = new Scene(layout);
scene.getStylesheets().add(CSS);
stage.setScene(scene);
stage.show();
inputField.requestFocus();
clientExecutor.submit(client);
}
private void logMessage(ListView<String> messageView, String request) {
messageView.getItems().add(request);
messageView.scrollTo(Math.max(0, messageView.getItems().size() - 1));
}
private void closeApp(Scene scene) {
Parent root = scene.getRoot();
root.setDisable(true);
FadeTransition fade = new FadeTransition(Duration.seconds(1), root);
fade.setToValue(0);
fade.setOnFinished(e -> Platform.exit());
fade.play();
}
@Override
public void stop() {
clientExecutor.shutdown();
serverExecutor.shutdown();
}
public static void main(String[] args) {
launch();
}
}
這篇關于如何將對象從inputStream客戶端返回到JavaFX控制器?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,