我目前正在设计一个程序,其中部分程序文件在Raspberry Pi上运行,另一部分在我的计算机上运行。
要在它们之间进行通信,我通过TCP / IP发送消息。
因此,要阅读传入的消息,我使用(read port)
。然后我做了一些计算并发回答案。
现在我注意到,当答案是一个数字时,我在另一方面没有得到答案(我不知道是不是因为它是一个数字或不是,我认为它是)。虽然它已被发送。然后它会导致不正确的读取(我想因为它仍然在缓冲区中)。
这就是我发送消息的方式:
#lang racket
; Not important
(require (rename-in racket/tcp
(tcp-connect racket-tcp-connect)
(tcp-listen racket-tcp-listen)))
(define (tcp-connect adress port)
(let-values ([(port-in port-out) (racket-tcp-connect adress port)])
(cons port-in port-out)))
;;;;
(define ports (tcp-connect "localhost" 6667))
(define in (car ports))
(define out (cdr ports))
(define (send destination message expectAnswer? . arguments)
(write-byte destination out) ; Send the destination (is a number < 256) (so that I know on the other side which object I have to send the message to).
(newline out) ; I noticed that if I don't do this, sometimes the message won't be sent.
(write message out)
(newline out)
(write arguments out)
(newline out)
(write expectAnswer? out)
(newline out)
(flush-output out)
(display "destination : ") (display destination) (newline)
(display "Message : ") (display message) (newline)
(display "Arguments : ") (display arguments) (newline)
(display "Expects an answer? ") (display expectAnswer?) (newline)
(when expectAnswer?
(let ((answer (read in)))
(if (eof-object? answer)
'CC ; CC = Connection Closed
(begin (display "Answer : ")(display answer)(newline)(newline)
answer)))))
这就是我如何阅读传入消息(在Raspberry Pi上)并发回答:
#lang racket
; Not important
(require (rename-in racket/tcp
(tcp-listen racket-tcp-listen)
(tcp-accept racket-tcp-accept)))
(define (tcp-accept port)
(let-values ([(port-in port-out) (racket-tcp-accept (racket-tcp-listen port))])
(cons port-in port-out)))
;;;;
(define ports (tcp-accept 6667))
(define in (car ports))
(define out (cdr ports))
(define (executeMessage destination message argumentList expectAnswer?)
(let ((destinationObject (decode destination)) ; This is the object that corresponds to the number we received
(answer '()))
(if (null? argumentList)
(set! answer (destinationObject message))
(set! answer (apply (destinationobject message) argumentList)))
(display "Destination : ")(display destination)(newline)
(display "Message : ")(display message)(newline)
(display "Arguments : ")(display argumentList)(newline)
(display "Expects answer? ")(display expectAnswer?) (newline)
(display "Answer : ")(display answer)(newline)(newline)
; We send the answer back if it is needed.
(when expectAnswer?
(write answer out)
(newline out) ; Because I noticed that if I don't to this, it won't be sent.
(flush-output out))))
; We call this function to skip the newlines that are send "(newline out)"
(define (skipNewline)
(read-byte in))
(define (listenForMessages)
(when (char-ready? in) ; Could be omitted.
; A message was sent
(let ((destination (read-byte in))
(message (begin (skipNewline) (read in)))
(argumentList (begin (skipNewline) (read in)))
(expectAnswer? (begin (skipNewline) (read in))))
(skipNewline)
(executeMessage destination message argumentList expectAnswer?)))
(listenForMessages))
(listenForMessages)
运行程序时,我看到正在发送和回答的一堆邮件。 但后来我看到一条消息,希望得到一个答案并且不会得到答案。 这就是覆盆子pi上显示的内容:
Destination : 2
Message : getStationHoogte
Arguments : '()
Expects answer? #t
Answer : 15
所以消息被执行了,结果是15(我检查了它,它应该产生的结果,所以到目前为止我很高兴。)
请注意,Answer : ...
的显示恰好在发送答案之前发生。
但是在我的电脑上我读到了这个:
Destination : 2
Message : getStationHoogte
Arguments : ()
Expects answer? #t
Answer :
我觉得非常奇怪的是 答案是什么? 怎么可能?我用&#34;读&#34;为了阅读传入的答案,这是一个阻止操作。它怎么能检测到答案(在本例中我会假设为15)(因为它停止了阻塞)但却产生了#34;什么都没有&#34;。
这种行为可能是什么原因?消息(在这种情况下是一个数字)不能发送的原因是什么?
答案 0 :(得分:2)
将(display answer)
替换为(write answer)
以查看打印内容。
答案 1 :(得分:1)
虽然我无法告诉您发布的确切问题,但我有几点建议:
您可以define-values
使用tcp-connect
的结果,如下所示:
(define-values (in out) (tcp-connect "localhost" 6667))
每条消息成为单个write
和read
可能更简单,更可靠。为此,只需将所有值放在list
(或#:prefab
struct
)中。您可以使用match
轻松再次提取元素。例如像这样的东西(我没有经过/测试过):
(define (send destination message expect-answer? . arguments)
(write (list destination message expect-answer? arguments)
out)
(newline out) ;do you actually need this?
(flush-output out) ;you definitely do want this!
(when expect-answer?
(match (read in)
[(? eof-object?) 'CC] ; CC = Connection Closed
[answer (printf "Answer : ~a\n" answer)])))
(define (listen-for-messages)
(match (read in)
[(? eof-object?) 'CC]
[(list destination message expect-answer? arguments)
(execute-message destination message arguments expect-answer?)
(listen-for-messages)]))
有关换行的更新:
现在您已经write
和read
s-expressions(list
s),分隔邮件不需要换行符 - 现在提供括号相反,那个角色。
重要的是缓冲 - ergo flush-output
。并且当expect-answer?
为#t
时,请确保在任何代码运行中使用它。
顺便说一句,您可以使用file-stream-buffer-mode更改某些端口(包括TCP端口)的缓冲模式。默认情况下它可能是'block
,这也是您之前需要换行的原因。如果您将模式更改为'line
,则可能会有效。但是现在你正在使用s表达式,我认为它不重要。您应该在发送每条消息(或答案)后使用flush-output
。