我想知道如何实现一种"远程方法调用"(以非常简单的形式)。我正在以面向对象的方式编写程序。我有一些生活在树莓派上的物体,还有一些生活在电脑上的物体。所以有时我想从电脑上的对象向树莓派上的对象发送消息。到目前为止,没有什么太难的。但是当我希望该消息有结果时,我被卡住了。
例如,如何实现我的计算机上的一个对象向树莓派发送带有参数3和4的消息"add",并期望得到结果(7)?
我制作了一个协议,通过TCP向对象发送消息和参数。但是,如果预期结果,我的Raspberry Pi上的对象将不得不通过TCP发送一条新消息来回答。但是我怎样才能得到答案呢
我可以使用/进行阻塞操作,将消息发送到Raspberry Pi并等待,直到返回结果。但在模拟程序中,我想这不是你想要的。
因此,我在思考如何在不执行阻塞操作的情况下实现这一点我想出了这个:
我可以用"消息表"扩展负责通信的对象(通过TCP)。在该表中,我可以为每条消息存储ID、消息本身、目标对象(在树莓pi上)和结果
因此,现在,如果我想发送消息"getNumber"(它随机返回一个数字),我将调用带有消息和目的地的通信对象。它将用唯一的ID、消息和目的地填充表格在某个时刻,目标对象将完成计算并返回结果为此,它将通过TCP将其答案发送到通信对象,该对象将填充表中的结果从那一刻起,人们可以通过传递ID来请求消息的结果。通信对象所要做的就是从他的表中读取结果。
如果没有通过TCP/IP进行通信,它将看起来像:
(destination-object 'get-number) ; Results in a number, with TCP this could not have a result because the result itself also has to be send over TCP.
具有如上所述的通信:
(define id ((communication-object 'send-message) "get-number" "destination-object"))
(define result ((communication-object 'get-result) id))
因为我从来没有制作过一个通过TCP/IP进行通信的程序,我想知道这是否是处理消息及其结果的好方法,或者是否有更好/更容易的方法
知道我正在Racket中编写程序,也许使用当前延续的调用是实现这一点的更容易的方法(如果可能的话)?通过保留"未来"(还有什么要做)直到结果揭晓。
如果您想利用这个领域的其他工作,您可以使用REST API。
这基本上使用了HTTP协议的机制,该协议运行在TCP之上,是浏览器用于连接网站的主要协议,为主机上的服务提供类似API的网络。返回结果是该体系结构的标准部分。
它不像TCP之上的自定义协议那样轻量级,但另一方面,您将能够利用所有内置的错误和边缘案例处理,以及大型用户社区。
有相当多的指南可用于复盆子上的REST:
- https://thefloppydisk.wordpress.com/2013/05/08/how-to-build-a-restful-web-api-on-a-raspberry-pi-in-javascript/
- http://www.instructables.com/id/Building-a-Web-Enabled-Door-Lock-using-Rest-API-an/
- http://www.gaggl.com/2014/04/raspberrypi-real-world-control-with-rest-api/
一种可能的方法是每个请求到Raspberry Pi建立一个连接,两端每个连接建立一个线程。所以在电脑上,你的发送信息会被定义为这样的:
(define (send-message message-name . args)
(let-values ((in-port out-port) (tcp-connect rasp-pi-addr port))
; Assuming you're sending Lisp values across the network
(write (cons message-name args) out-port)
(let ((result (read in-port)))
(close-input-port in-port)
(close-output-port out-port)
result)))
然后,当你想向Raspberry Pi发送请求时,你会在一个线程中完成:
(thread (λ () (async-channel-put result-channel
((communication-object 'send-message) "get-number" "destination-object"))))
然后,在执行此操作时,程序的其余部分将可以自由继续运行。你也可以在线程中对结果做任何你想做的事情,而不是让主线程等待结果:
(thread (λ ()
(update-opponent-position
((communication-object 'send-message) "opponent" "make-move"))))
根据您的程序所做的工作,这可能会使您最大限度地减少所需的重新设计。
需要注意的是,Racket的线程不是真正的CPU线程,因此使用它们不会从处理器的多核中获益。但它们非常适合并行化I/O绑定任务。