我正在用Java开发一个小型客户端-服务器程序。
客户端和服务器通过一个tcp连接进行连接。通信的大多数部分是异步的(可以在任何时候发生),但有些部分我希望是同步的(比如发送命令的ACK)。
我使用一个线程从套接字的InputStream中读取命令,并引发一个onCommand()事件。命令本身由命令设计模式进行。
什么是最佳实践方法(Java),可以在不错过其他可能同时出现的命令的情况下等待ACK?
con.sendPacket(new Packet("ABC"));
// wait for ABC_ACK
编辑1
把它想象成一个FTP连接,但数据和控制命令都在同一个连接上。我想在后台运行数据流时捕捉对控制命令的响应。
编辑2
所有内容都以块为单位发送,以便在同一TCP连接(多路复用)上进行多次(不同)传输
Block:
1 byte - block's type
2 byte - block's payload length
n byte - block's paylod
原则上,您需要一个被阻止线程的注册表(或者更好的是,它们正在等待的锁),用一些将由远程端发送的标识符进行键控。
对于异步操作,您只需发送消息并继续。
对于同步操作,在发送消息后,您的发送线程(或启动此操作的线程)会创建一个锁对象,将其与某个密钥一起添加到注册表中,然后等待锁,直到收到通知。
当读取线程接收到一些答案时,它会在注册表中查找锁对象,将答案添加到其中,并调用notify()
。然后读取下一个输入。
这里的难点是正确的同步,以避免死锁和丢失通知(因为它在我们将自己添加到注册表之前就回来了)。
当我为Fencing小程序实现远程方法调用协议时,我做了类似的事情。原则上,RMI以相同的方式工作,只是没有异步消息。
@Paulo的解决方案是我以前使用过的。然而,可能有一个更简单的解决方案。
假设您没有后台线程读取连接中的结果。相反,您可以使用当前线程来读取任何结果。
// Asynchronous call
conn.sendMessage("Async-request");
// server sends no reply.
// Synchronous call.
conn.sendMessage("Sync-request");
String reply = conn.readMessage();