sockets - JavaFX 套接字处理

标签 sockets javafx

尝试说明情况:

我创建了一个 SocketManager 类。这扩展了 JavaFX 服务,旨在创建新线程(我扩展并称为 SocketListener 的 JavaFX 任务)来处理特定的套接字连接。

在 SocketListener 中,我有一个循环监听套接字上的输入(并回复给客户端)。

问题 : SocketListener 中的循环正在阻塞(显然)。这意味着我永远不会到达 Socket Listener(它扩展 JavaFX Task)的 call 方法中的“返回”。
我很好奇要实现什么模式,以便我可以从 SocketListener 返回一个值,而不必中断与客户端保持连接的循环。想到的一个想法是创建一个自定义事件以在每条消息通过套接字时触发,但我想确保我实现的任何内容不仅“有效”而且是最佳的。

这是我引用的两个类的代码:

import javafx.concurrent.Service;
import javafx.concurrent.Task;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * The primary class for listening for and issuing communication over sockets in VDTS
 * applications.
 * WARNING: This class is blocking, and should be run in a separate thread.
 */
public class SocketManager extends Service<SocketMessage> {

    /**
     * The port that SocketManager instance will listen on.
     */
    int listenPort;

    /**
     * The ServerSocket instance used by SocketManager for receiving socket connections.
     */
    ServerSocket server;

    /**
     * Constructs a SocketManager and begins listening on the given port.
     * @param listenPort The port that the SocketManager instance will listen on.
     */
    public SocketManager(int listenPort){
        this.listenPort = listenPort;
        try {
            this.server = new ServerSocket(listenPort);
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
            //TODO
        }
    }

    /**
     * Returns the port currently being listened to by SocketManager instance.
     * @return the port being listened to.
     */
    public int getListenPort() {
        return listenPort;
    }

    /**
     * Sets a new port for the SocketManager instance to listen to. This will destroy
     * the current ServerSocket, ending any communication via the old instance. Use
     * with caution.
     * @param listenPort The new port this SocketManager instance will listen on.
     */
    public void setListenPort(int listenPort) {
        this.listenPort = listenPort;
    }

    @Override
    protected Task createTask() {
        String returnedMessage;
        Socket client;
        SocketListener messenger;
        while(true){
            try {
                client = null;
                client = server.accept();
                messenger = new SocketListener(client);
                new Thread(messenger).start();
            } catch (IOException ex) {
                System.out.println(ex.getMessage());
                //TODO
            }
        }
    }
}

和另一个
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

/**
 * An extension on javafx.concurrency.Task.
 * SocketListener is responsible for retrieving a message (string) from a client over
 * the socket and returning this string (Usually to a SocketManager).
 */
public class SocketListener extends javafx.concurrent.Task<String> {

    /**
     * Client socket which is referenced for persistent communication.
     */
    private final Socket client;

    /**
     * PrintWriter used to write to client.
     */
    private PrintWriter clientOut;

    //TODO This is a temporary property for testing, remove it;
    private int messageCount = 0;

    /**
     * Constructs a SocketListener given a client (Socket)
     * @param client
     */
    public SocketListener(Socket client){
        this.client = client;
        try {
            this.clientOut = new PrintWriter(client.getOutputStream(), true);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Listens for and returns the value of the message received over socket.
     * @return The message received from the client.
     * @throws Exception
     */
    @Override
    protected String call() throws Exception {
        String nextLine = null;
        BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
        //TODO remove in production should not require highfive
        clientOut.println("Just saying hi.");
        while ((nextLine = in.readLine()) != null) {
            this.messageCount++;
            clientOut.println("You've messaged me " + this.messageCount + " times.");
        }
        return "Socket closed.";
    }
}

最佳答案

为什么不尝试使用其他选项?通过套接字输入和输出数据的标准库效率不高(java.net)。你可以试试 Java NIO library ,这将为您的代码提供更大的灵活性。

NIO 为您提供了启动连接的能力,因此您可以选择您的代码是否会阻止您的连接,但您必须使用循环。在循环内部,您可以观察两点之间进行了什么类型的通信,然后根据需要处理通信。然而,只要有更多的创造力,您就可以在服务器端使用 executors 服务,从而导致其他线程只需要处理通信,只剩下一个线程来负责通信或交换数据。

JavaFX 是一种技术,它为开发丰富的应用程序带来了很好的工具。由于它被认为是一种不同类型的技术并使用另一种方法,因此 JavaFX(如 Swing)带来了一些工具来确保您的代码线程安全,这正是 Task , Service ,其中包括 runLater方法来自 Platform .

所以你所能做的就是混合这两种技术,NIO 和 JavaFX。现在你要在你的应用程序中做一些处理,无论是客户端还是服务器,在除 JavaFX Application Thread. 之外的线程上执行处理。当您必须在 JavaFX 应用程序中显示数据时,只需为此使用 JavaFX 应用程序线程。世界上没有比这更简单的事情了。 ;)

如果蔚来技术不合你意,你仍然可以尝试其他“更好”开发的技术,比如Apache MINA projectNETTY framework .这些项目为任何使用 NIO 的人开发了更实用的解决方案,它们非常有用,因为您不必重新发明轮子。

如果您仍有疑问,请提问。祝你好运。 (:

关于sockets - JavaFX 套接字处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21299241/

相关文章:

在 c : include file not found 中编译

c - 为什么 select() 在第一次超时后总是返回 0

c++ - 10038 套接字错误

java - macOS 下 JavaFX WebView 的显示不正确

JavaFX ScrollBar setOnMousePressed 不工作

java - 在 Java 中减少二维数组

java - 如何每分钟从客户端向服务器发送一个字符串(循环)一次?

android 异步任务 NetworkOnMainThreadException

JavaFX TextField 对用户输入使用react,但对 setText() 不使用react

java - 为什么 TableView 不显示从其他列计算值的列值?请给我建议一些解决方案