12

我的问题:我将 802.15.4 无线网络连接到串行端口(使用包装器)。我可以将包发送到网络并监听传入的包。你可以想象这是高度异步的。

任务来了:我想向网络发送命令并在一个函数调用中等待响应。例如:我想从网络 ID 为 1338 的节点获取温度。

double getTemperature(int id) throws Exception { .... }

除了做所有这些“同步(对象)等待(..)通知(..)”的东西之外,还有更好的方法来等待响应消息吗?

最好的问候,比格博恩

也许添加一些香料:

这一切都应该以用户可以请求这些命令(通过 ajax 或直接)的 web 界面结束。我还考虑过在数据库中缓存响应值。但是对于某些命令,您必须直接回答成功/失败

4

3 回答 3

7

您可以使用 BlockingQueue 执行此操作,因此您不必手动管理任何同步。请求可以发送消息,然后在 BlockingQueue 上调用 take(),等待元素出现。该元素是在返回回复时由端口上的任何侦听器插入到队列中的回复。

您只需要协调,以便侦听器和请求者共享同一个队列。对于每个请求,您只需要一个大小为 1 的队列即可支持此方案。

// Send method
BlockingQueue<Reply> q = new ArrayBlockingQueue<Reply>(1);
serialCom.registerQueue(myRequest.getId());
serialCom.sendRequest(myRequest);
return q.take();

//Listener
BlockingQueue<Reply> q = queueMap.get(incomingMessage.getId());
q.add(incomingMessage.getReply());
于 2010-10-04T16:55:35.603 回答
2

我不确定我是否正确理解了这个问题,但我通常将 aFuture<T>用于这类任务。

在内部,Future<T>实现使用等待和通知以及所有这些,但接口本身变得相当干净。

Future<Double> getTemperature(int id);

然后,在您的通信代码中,您可以将传入的消息映射到未完成的未来。如果保证订购,您可以执行类似的操作

class Something {
    Map<Integer, Queue<Object>> requests;

    synchronized Future<?> request(int id, Object data) {
        MyFutureImpl future = new MyFuture();
        requests.get(id).add(future);
        serializeAndSend(id, data);
        return future;
    }

    void serializeAndSend(id, data) {...}

    synchronized void response(int id, Object data) {
        MyFutureImpl future = requests.get(id).remove();
        future.setValue(data); // This would fulfill the future, and any
                               // threads waiting in a get() will get the
                               // value and continue.
    }
}

MyFutureImpl 是一个非常基本的未来实现。我假设有一个通信线程response()在收到数据包时调用。我还假设serializeAndSend()-function 处理对客户端的写入或阻塞,直到可以进行写入操作或将其移交给通信线程。

使用具有并发能力的映射和队列结构可以使一些synchronizations 变得不必要。如果每个 id 只有一个未完成的呼叫,那么队列当然就变得不必要了。

于 2010-10-04T13:35:05.917 回答
1

更好的方法是将它包装在一些可重用的请求/响应类中。这样你就可以有一个标准的方式来查询串口并等待响应。然而,这个类无疑必须在其实现中的某处使用 synchronized 关键字并等待和通知命令。这是编写 Java 的关键部分,了解它们的工作原理很重要。

如果你要设计一个你说的函数,你必须确保你从一个可以阻塞等待结果的线程调用它。该函数必须在其内部实现某种等待循环,等待来自串行端口的响应。所以重要的是它运行的任何线程也能够等待。

这也带来了额外的一点。如果您有多个线程这样做,您将需要一些类来处理串行端口通信,该类可以处理来自多个线程的多个请求并根据需要将它们排队以处理串行端口和特定设备的异步性质您正在连接的。例如,在第一个命令的响应被完全读取之前发送第二个命令可能是不合适的。

这里有几个复杂的问题,重要的是要有一个好的设计,以合理的方式解决这些问题。

于 2010-10-04T13:03:35.517 回答