球拍,在不知道什么的情况下从端口读取输入
Racket, reading input from a port without knowing what
我目前正在设计一个程序,其中部分程序文件 运行 在 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)
当 运行 运行程序时,我看到发送了一堆消息并正确回答了。
但后来我看到一条消息,希望得到答案,但没有得到答案。
这是 raspberry pi 上显示的内容:
Destination : 2
Message : getStationHoogte
Arguments : '()
Expects answer? #t
Answer : 15
所以消息被执行了,结果是 15(我检查了它,这是它应该产生的结果,所以到目前为止我很高兴)。
请注意 Answer : ...
的显示恰好发生在发送答案之前。
但是在我的电脑上我看到了这个:
Destination : 2
Message : getStationHoogte
Arguments : ()
Expects answer? #t
Answer :
我觉得很奇怪的是答案什么都没有?
这怎么可能?我使用 "read" 来读取收到的答案,这是一个阻塞操作。它怎么会检测到一个答案(我假设在这个例子中是 15 个)(因为它停止阻塞)并产生 "nothing".
这种行为的原因可能是什么?未发送消息(在本例中为数字)的原因可能是什么?
将 (display answer)
替换为 (write answer)
以查看打印的内容。
虽然我无法从您发布的内容中判断出确切的问题是什么,但我有几点建议:
您可以将 define-values
与 tcp-connect
的结果一起使用,如下所示:
(define-values (in out) (tcp-connect "localhost" 6667))
将每条消息设为单个 write
和 read
可能更简单、更可靠。为此,只需将所有值放入 list
(或者可能是 #:prefab
struct
)中。您可以使用 match
轻松再次提取元素。例如像这样的东西(我没有run/tested):
(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
ing 和 read
ing s 表达式 (list
s),不需要换行符来分隔消息 -- 括号现在起到了这个作用相反。
的作用是缓冲 -- 因此 flush-output
。当 expect-answer?
为 #t
时,请务必在运行的任何代码中使用它。
顺便说一句,您可以使用file-stream-buffer-mode更改某些端口(包括TCP端口)的缓冲模式。默认情况下可能是 'block
,这就是为什么你之前需要换行符。如果您将模式更改为 'line
,它可能会起作用。但既然您使用的是 s 表达式,我认为这应该无关紧要。您应该在每条消息(或回复)发送后使用 flush-output
。
我目前正在设计一个程序,其中部分程序文件 运行 在 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)
当 运行 运行程序时,我看到发送了一堆消息并正确回答了。 但后来我看到一条消息,希望得到答案,但没有得到答案。 这是 raspberry pi 上显示的内容:
Destination : 2
Message : getStationHoogte
Arguments : '()
Expects answer? #t
Answer : 15
所以消息被执行了,结果是 15(我检查了它,这是它应该产生的结果,所以到目前为止我很高兴)。
请注意 Answer : ...
的显示恰好发生在发送答案之前。
但是在我的电脑上我看到了这个:
Destination : 2
Message : getStationHoogte
Arguments : ()
Expects answer? #t
Answer :
我觉得很奇怪的是答案什么都没有? 这怎么可能?我使用 "read" 来读取收到的答案,这是一个阻塞操作。它怎么会检测到一个答案(我假设在这个例子中是 15 个)(因为它停止阻塞)并产生 "nothing".
这种行为的原因可能是什么?未发送消息(在本例中为数字)的原因可能是什么?
将 (display answer)
替换为 (write answer)
以查看打印的内容。
虽然我无法从您发布的内容中判断出确切的问题是什么,但我有几点建议:
您可以将
define-values
与tcp-connect
的结果一起使用,如下所示:(define-values (in out) (tcp-connect "localhost" 6667))
将每条消息设为单个
write
和read
可能更简单、更可靠。为此,只需将所有值放入list
(或者可能是#:prefab
struct
)中。您可以使用match
轻松再次提取元素。例如像这样的东西(我没有run/tested):(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
ing 和 read
ing s 表达式 (list
s),不需要换行符来分隔消息 -- 括号现在起到了这个作用相反。
的作用是缓冲 -- 因此 flush-output
。当 expect-answer?
为 #t
时,请务必在运行的任何代码中使用它。
顺便说一句,您可以使用file-stream-buffer-mode更改某些端口(包括TCP端口)的缓冲模式。默认情况下可能是 'block
,这就是为什么你之前需要换行符。如果您将模式更改为 'line
,它可能会起作用。但既然您使用的是 s 表达式,我认为这应该无关紧要。您应该在每条消息(或回复)发送后使用 flush-output
。