java - Java中两个状态机之间的通信

标签 java automata state-machine statechart

我一直在使用一个简单的 eclipse 插件来创建可视状态机,名为 statecharts ,也使用 Java 代码来工作。我的总体目标是使两个状态机通过套接字相互通信并交换数据并基于此进行转换,例如客户端-服务器通信。 一开始我使用简单的同步客户端-服务器代码,但显然使用同步方法无济于事;正确的方法是不断地从队列中轮询数据。我现在正在尝试使用 Java NIO,这看起来很有希望,但不幸的是第一次尝试没有成功。似乎某个地方有一个繁忙的循环,不允许接收到的值触发更改。

代码非常简单:我首先尝试连接到服务器(它有效),发送数据(它有效),并尝试每个周期从输入缓冲区读取数据作为接收数据的方式,如您在图片。到目前为止的逻辑是有道理的。我将接收到的数据设置为一个变量,该变量也位于转换表达式中。所以基本上只要它被设置为真,我就应该转移到下一个状态。但它不起作用。

有人可以帮我解决这个问题吗?我见过像 Netty 这样的异步 API和 Naga如果这是一种补救措施,事情可能会变得更容易。

这是状态机的可视化方案: enter image description here

这是客户端的代码:

package test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

public class EchoClient2 {
    String serverHostname = new String("127.0.0.1");
    BufferedReader stdIn;
    Socket echoSocket = null;
    PrintWriter out = null;
    BufferedReader in = null;

    public void open(){
        System.out.println("Attemping to connect to host " + serverHostname
                + " on port 5555.");
        try {
            echoSocket = new Socket(serverHostname, 5555);
            out = new PrintWriter(echoSocket.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(
                    echoSocket.getInputStream()));
        } catch (UnknownHostException e) {
            System.err.println("Don't know about host: " + serverHostname);
        } catch (IOException e) {
            System.err.println("Couldn't get I/O for " + "the connection to: "
                    + serverHostname);
        }
    }

    public void send(){
        String userInput = "1";
        out.println(userInput);
    }

    public String receive(){
        String result = "";
        try {
            result = in.readLine();
            if(result==null)
                return "0";
        } catch (IOException e) {
        }
        return result;
    }
}

这是服务器的代码:

package test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class EchoServer extends Thread {
    protected Socket clientSocket;

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = null;

        try {
            serverSocket = new ServerSocket(5555);
            System.out.println("Connection Socket Created");
            try {
                while (true) {
                    System.out.println("Waiting for Connection");
                    new EchoServer(serverSocket.accept());
                }
            } catch (IOException e) {
                System.err.println("Accept failed.");
                System.exit(1);
            }
        } catch (IOException e) {
            System.err.println("Could not listen on port: 5555.");
            System.exit(1);
        } finally {
            try {
                serverSocket.close();
            } catch (IOException e) {
                System.err.println("Could not close port: 5555.");
                System.exit(1);
            }
        }
    }

    private EchoServer(Socket clientSoc) {
        clientSocket = clientSoc;
        start();
    }

    public void run() {
        System.out.println("New Communication Thread Started");

        try {
            PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),
                    true);
            BufferedReader in = new BufferedReader(new InputStreamReader(
                    clientSocket.getInputStream()));

            String inputLine;

            while ((inputLine = in.readLine()) != null) {
                System.out.println("Server: " + inputLine);
                out.println(inputLine);

                if (inputLine.equals("Bye."))
                    break;
            }

            out.close();
            in.close();
            clientSocket.close();
        } catch (IOException e) {
            System.err.println("Problem with Communication Server");
            System.exit(1);
        }
    }
}

here 是 Eclipse 项目文件夹,您可以简单地导入它(如果这样更容易的话)。

最佳答案

您打算做的事情背后的数学称为 PI 微积分。这不是唯一的方法,但它是一个很好的起点。

基本上,您将建模的是一种关系,其中两台机器可以进入相关状态,并且在发生共享条件(通常是传递消息)之前不会继续进行。

这意味着您必须将两个状态机置于不同的线程上。尝试使用公共(public)事件队列对机器进行排序,如果排序不稳定,这可能会变得非常有问题(如果排序与某个问题不互补,问题可能会更大)。

共享的消息通常会被简化。例如,许多系统使用“邮箱”类型的传递机制,其中一个状态机将消息传递到另一个状态机的入站邮箱。然后发送状态机会阻塞,直到消息清除邮箱为止。如果您以正确的方式将其形式化,您就可以有效地创建一个类似 Actor 的解决方案。如果您决定采用这种方式,那么尽早在邮箱中进行烘焙将允许您稍后用持久消息传递系统替换该类。

就实际使其与两个独立进程一起工作而言,我最喜欢的方法是让第三个进程启动这两个进程,其中启动进程还创建任何所需的通信 channel 。然后,该启动进程可以设置其两个子进程的可配置元素。以这种方式做事可能需要一些关于如何创建“系统服务”(又名没有 tty 的程序)的知识,但拥有这些知识是很好的。另外,我更喜欢 JMS API 和众多实现之一。

如果你真的想“推出自己的”,那么我会从比完整的 NIO 解决方案稍微少一点的东西开始。请记住,当您具有某些通信模式时,NIO 可以很好地扩展,但是阻塞所需输入(或所需传递确认)的单个状态机不需要跨线程池进行扩展或等待复杂的事件回调。当然,其他人可能有不同的意见,但某些工作流程使用可扩展性较差的解决方案可以更快地进行基准测试(我认为这可能是一项可扩展性不会给你带来太多好处的工作,除非你真的代理了数十个或多个网络的通信)同一进程中有数百个状态机)。

关于java - Java中两个状态机之间的通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33350990/

相关文章:

java - 使用 recyclerview 和 firebase 时出现错误 : Adapter not attached, 跳过布局到类

java - Netty 写入所有连接的 channel

java - 警告 : Action does not match allowed action names pattern, 清理它

java - 用于从给定 DFA 打印所有接受的字符串(如果数量无限则为上限)的算法

java - 在不同状态之间传输数据

python - 如何为 `transitions` 状态机定义触发器枚举?

java - 如何从Firebase数据库Android获取子节点

automata - {w in {a, b}* | 强化学习关系中有多少个等价类? (#a(w) mod m) = ((#b(w)+1) mod m)}

javascript - 除了 ECMAScript 规范中提供的上下文无关语法之外,是否还有其他方法可以将 JavaScript 词法化为 token ?

uml - BoUML 的状态机生成器是否正确处理复合状态的退出和进入?