编辑了我的问题以进行澄清和编码:
我的目标是将String数据从后台线程传递到我的主应用程序线程。任何帮助表示赞赏。
这是创建主后台线程的代码。这位于我的Server.java类中
public class Server {
boolean isConnected = false;
Controller controller = new Controller();
public void startHost() {
Thread host = new Thread(() -> {
Controller controller = new Controller();
ServerSocket server = null;
try {
server = new ServerSocket(GeneralConstants.applicationPort);
} catch (BindException e2) {
System.out.println("Port Already in Use!");
} catch (IOException e) {
//do nothing
}
while (true) {
if (server == null) { break; }
try {
Socket client = server.accept();
System.out.println("Client Connected: " + isConnected);
if (!isConnected) {
controller.createClientHandler(client);
isConnected = true;
System.out.println("Client Connected: " + isConnected);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
host.setDaemon(true);
host.start();
}
这是连接客户端后在我的Controller.java类中调用的代码。
public synchronized void createClientHandler(Socket client) {
boolean alreadyConnected = false;
if (alreadyConnected) {
//do NOT assign multiple threads for each client
} else {
ClientHandler handleClients = new ClientHandler("client", client);
}
}
然后程序为我的客户端创建了两个后台线程,一个用于管理接收消息和发送消息。
public ClientHandler(String name, Socket s) {
clientSocket = s;
clientName = name;
receiveThread = new Thread(this::receive);
sendThread = new Thread(this::send);
connected = clientSocket.isConnected();
receiveThread.start();
sendThread.start();
}
然后,线程成功创建输入流,并将对象传递给我的控制器。然后处理并抓取将其分配给变量的字符串
public synchronized void handleReceivedPacket(String name, BufferedReader in) {
try {
data = in.readLine();
System.out.println("Successfully assigned data to: " + data);
} catch (IOException e) {
System.out.println("Unable to read result data");
}
}
如何在不获取null的情况下从主线程访问我的String数据?
我也可以打电话(或类似的电话)
controller.returnData();
从我的主应用程序。从中它要么返回null(还没有数据),要么实际上返回我的数据。现在,它总是空。
编辑,这实际上是在调用controller.returnData(){
由于不想达到StackOverflow的代码限制,我不想粘贴大量的代码,所以这是我的应用程序结构。
我的JavaFX创建场景,并创建一个根网格窗格,然后调用一个方法,该方法根据指定的输入创建子网格窗格。又名,用户可以按“主菜单”,该方法调用我的方法setScene(),该方法将删除当前的“子根”网格窗格并创建一个“新”场景。现在,我有一个GameBoard.java类,它在按下按钮时调用controller.returnData()
PassOption.setOnAction(event -> {
System.out.println(controller.returnData());
});
除了测试之外,没有其他功能目的。如果我可以接收数据,则可以使用数据对此进行扩展。
答案 0 :(得分:0)
开始考虑设计。在网络应用程序中,通常必须管理以下职责:
将这些职责分开以保持代码的清洁,可读和可维护是有意义的。
分离可以同时表示线程和类。
例如,您可以按以下方式实现它:
类ClientAcceptor
负责打开套接字并接受客户端。客户端连接后,它将进一步的工作委托给控制器,然后等待其他客户端:
public class ClientAcceptor implements Runnable {
@Override
public void run() {
while (true) {
ServerSocket server;
try {
server = new ServerSocket(1992);
Socket client = server.accept();
if (client.isConnected()) {
controller.createClientHandler(client);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
然后,控制器可以创建一个处理程序(如果控制器决定这样做,例如它也可以拒绝该客户端)。 ClientHandler
类的外观如下:
public class ClientHandler {
private Thread receiveThread;
private Thread sendThread;
private boolean connected;
private Socket clientSocket;
private String clientName;
private LinkedBlockingDeque<byte[]> sendQueue;
public ClientHandler(String name, Socket s) {
clientSocket = s;
clientName = name;
receiveThread = new Thread(() -> receive());
sendThread = new Thread(() -> send());
connected = clientSocket.isConnected();
receiveThread.start();
sendThread.start();
}
private void receive() {
BufferedInputStream in = null;
try {
in = new BufferedInputStream(clientSocket.getInputStream());
} catch (IOException e) {
connected = false;
}
while (connected) {
try {
byte[] bytes = in.readAllBytes();
if (bytes != null && bytes.length > 0) {
controller.handleReceivedPacket(clientName, bytes);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void send() {
BufferedOutputStream out = null;
try {
out = new BufferedOutputStream(clientSocket.getOutputStream());
} catch (IOException e) {
connected = false;
}
while (connected) {
byte[] toSend = sendQueue.getFirst();
if (toSend != null && toSend.length > 0) {
try {
out.write(toSend);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void send(byte[] packet) {
sendQueue.add(packet);
}
public void close() {
connected = false;
}
}
ClientHandler
负责接收和发送数据。如果数据包到达,它会通知控制器,后者将解析该数据包。 ClientHandler
还提供了一个公共API,用于发送数据(存储在队列中并由线程处理)并关闭连接。
以上代码示例未经测试,也不完整。以它为起点。