球拍,从端口读取输入而不知道是什么

时间:2015-04-06 18:16:23

标签: tcp port racket messages communicate

我目前正在设计一个程序,其中部分程序文件在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;。

这种行为可能是什么原因?消息(在这种情况下是一个数字)不能发送的原因是什么?

2 个答案:

答案 0 :(得分:2)

(display answer)替换为(write answer)以查看打印内容。

答案 1 :(得分:1)

虽然我无法告诉您发布的确切问题,但我有几点建议:

  1. 您可以define-values使用tcp-connect的结果,如下所示:

    (define-values (in out) (tcp-connect "localhost" 6667))
    
  2. 每条消息成为单个writeread可能更简单,更可靠。为此,只需将所有值放在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)]))
    

  3. 有关换行的更新:

    现在您已经writeread s-expressions(list s),分隔邮件不需要换行符 - 现在提供括号相反,那个角色。

    重要的是缓冲 - ergo flush-output。并且当expect-answer?#t时,请确保在任何代码运行中使用它。

    顺便说一句,您可以使用file-stream-buffer-mode更改某些端口(包括TCP端口)的缓冲模式。默认情况下它可能是'block,这也是您之前需要换行的原因。如果您将模式更改为'line,则可能会有效。但是现在你正在使用s表达式,我认为它不重要。您应该在发送每条消息(或答案)后使用flush-output