2015-04-06 71 views
1

我目前正在設計一個程序,其中一部分程序文件在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))))) 

而且我這是怎麼讀的傳入消息(上樹莓派)和發送答案回:

#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) 

運行程序時我看到一堆正在發送和回答的消息。 但是然後我看到一個消息,期望一個答案,並沒有得到一個。 這就是顯示在樹莓派:

Destination : 2 
Message : getStationHoogte 
Arguments : '() 
Expects answer? #t 
Answer : 15 

那麼被執行的消息,結果是15(我檢查了它,這就是它應該產生的結果,所以我很高興至今) 。

請注意,Answer : ...的顯示發生在發送答案之前。

但我的電腦上我讀到這樣的:

Destination : 2 
Message : getStationHoogte 
Arguments :() 
Expects answer? #t 
Answer : 

我覺得真的很奇怪的是,答案是什麼? 這怎麼可能?我使用「閱讀」來讀取傳入的答案,這是一個阻塞操作。它如何能夠檢測出一個答案(在這個例子中,我假設有15個答案)(因爲它停止了阻塞)並且產生了「無」。

這種行爲的原因是什麼?什麼可能是一個消息(在這種情況下是一個數字)沒有發送的原因?

+0

添加一個編程語言標籤 –

+0

我忘了,現在添加它;) – HyperZ

回答

1

雖然我不能從你貼什麼確切的問題是什麼告訴,我有幾個建議:

  1. 可以使用define-valuestcp-connect的結果,就像這樣:

    (define-values (in out) (tcp-connect "localhost" 6667)) 
    
  2. 它可能更簡單和更可靠的每個消息是一個單一的writeread。爲此,只需將所有值都放入list(或可能是#:prefabstruct)。您可以使用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 ING和荷蘭國際集團read s表達式(list s),不需要換行符來分隔消息 - 圓括號現在代替該角色。

什麼確實事情是緩衝 - ergo flush-output。當expect-answer?也是#t時,請務必在任何代碼運行中使用它。

順便說一下,您可以使用file-stream-buffer-mode更改某些類型的端口(包括TCP端口)的緩衝模式。可能它默認是'block,這就是爲什麼你以前需要換行符的原因。如果您將模式更改爲'line,它可能會有效。但是現在你正在使用s表達式,我認爲這不重要。在發送每條消息(或答案)之後,您應該只使用flush-output

+0

事實上,這爲我節省了很多問題!有人可以告訴我什麼時候需要發送換行符,什麼時候不行?因爲我注意到如果在每次寫入後我不發送換行符,我有時會遇到問題(錯誤的讀取)。 – HyperZ

+0

我更新了答案,重新換行。 –

2

(display answer)替換爲(write answer)以查看打印內容。

+0

謝謝,我會檢查它,當我回家! – HyperZ