我一直在使用一个简单的eclipse插件创建名为statecharts的可视状态机,该状态机也使用Java代码工作。我的总体目标是使两个状态机通过套接字相互通信并交换数据并基于此进行转换,例如客户端-服务器通信。
最初,我使用简单的同步客户端-服务器代码,但显然使用同步方法无济于事。正确的方法是连续轮询队列中的数据。我现在正在尝试使用看起来很有希望的Java NIO
,但不幸的是,第一次尝试没有成功。似乎某个地方有一个繁忙的循环,不允许接收到的值触发更改。
代码非常简单:我首先尝试连接到服务器(它可以工作),发送数据(它可以工作),然后尝试在每个周期从输入缓冲区读取数据,作为接收数据的一种方式,如图所示。到目前为止的逻辑是有道理的。我将接收到的数据设置为一个变量,该变量也位于转换表达式中。因此,基本上,每当设置为true时,我都应过渡到下一个状态。但这是行不通的。
有人可以帮我解决这个问题吗?我已经看到有像Netty和Naga这样的异步API,如果可以的话,它们可能会使事情变得更容易。
这是状态机的可视化方案:
这是客户端的代码:
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微积分。这不是唯一的方法,但它是一个很好的起点。
基本上,您要建模的关系是两台计算机可以进入相关状态并且直到共享条件发生(通常是正在传递的消息)后才进展。
这意味着您必须将两个状态机都放在单独的线程上。尝试使用公共事件队列对机器进行排序,如果排序不稳定,则可能会变得非常棘手(如果排序不能与某个问题互补,则可能会出现更大的问题)。
通常,共享消息会得到简化。例如,许多系统使用“邮箱”类型的传递机制,其中一种状态机将消息传递到另一种状态机的入站邮箱。然后,传递状态机将阻塞,直到消息清除邮箱为止。如果以正确的方式对此进行形式化,则可以有效地创建类似于Actor的解决方案。如果您决定以这种方式进行操作,则尽早在邮箱中进行烘焙将使您以后可以使用持久性消息传递系统替换该类。
至于实际上使它与两个独立的进程一起工作,我最喜欢的方法是让第三个进程启动这两个进程,启动过程还会创建任何需要的通信渠道。然后,启动过程可以设置它的两个孩子的可配置元素。用这种方式做事可能需要一些知识,即如何在没有ttys的情况下创建“系统服务”(又名程序),但是拥有这是一个很好的知识。另外,我更喜欢JMS API和许多实现之一。
如果您真的想“自己动手”,那么我将以比完整的NIO解决方案少一些的方式开始。请记住,当您具有某些通信模式时,NIO可以很好地扩展,但是阻塞所需输入(或所需传递确认)的单个状态机不需要跨线程池扩展或等待复杂的事件回调。当然,其他人的观点可能会有所不同,但是某些工作流程会使用可扩展性较低的解决方案来更快地进行基准测试(我认为这可能是一项工作,其中可扩展性不会给您带来多少好处,除非您真正代理数十个或数十个通信代理同一过程中的数百个状态机)。
关于java - Java中两个状态机之间的通信,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33350990/