2013年9月23日 星期一

[named pipe] 訊息傳送的協定 - 使用分隔字元

在之前的例子中,在訊息傳送使用的是 StreamWriter 類別,訊息接收使用的是 StreamReader 類別。
接下來就是要討論幾種訊息傳送接收的方式。

在之前的例子中,使用了 WriteLine 方法傳送訊息,及 ReadLine 方法接收訊息。
這代表傳送端及接收端都「同意」使用「換行」這個字元當做一個訊息的結束。

在早期使用無線電通話機時,兩邊的人都必須要在說完話之後,加一個「over」,
讓對方知道自方說完一句話。使用 WriteLine、ReadLine 也是一樣的道理。

然後,這種方式,會有什麼問題呢?

首先,我們來看看在訊息中有換行字元會發生什麼事?

為了要看清楚接下來的範例,要改一下程式。
在 Server 端及 Client 端,接收到訊息後會將訊息更新到 TextBox2,負責處理的函式如下:

Sub UpdateTextBox2State(ByVal desc As String)
    If Me.InvokeRequired Then
        Me.Invoke(deleUpdateTextBox2State, New Object() {desc})
    Else
        TextBox2.Text += DateTime.Now.ToString() & desc & vbNewLine
    End If
End Sub

原本是「TextBox2.Text += desc & vbNewLine」,在 desc 前加上時間綽戳記。
如此每收到一個訊息,就會連同時間戳記一起寫下,就可觀察到不同次收到的訊息為何。

接下來,在 server 端的 TextBox2 裡,填入以下文字:

named pipe 測試1
分隔符號在訊息中

image

按下 Send 鈕之後,Client 端的畫面為:

image

原來預期一次傳送的訊息,被接收端認為是兩次訊息。

訊息斷裂後的兩次訊息,對於人類來說是還好,但對於程式來說,一定會造成無法辨識的結果。

所以收送的兩方一定要嚴守通訊的要求,才不會有意外發生。

但是,有些情況下,非得要傳送這種訊息中有換行字元的,例如一首詩。
那麼最常使用的方式,就是把訊息中的換行字元替換成其他的字元。
換成其他字元的方法,可以解決換行字元的問題,但會衍生出「若訊息中,有『其他字元』該怎麼辦?」的問題。畢竟很難保證,訊息中不會有你用來取代換行字元的字元。於是實務上會看到許多工程師,會用兩個以上的字元來替代訊息中的換行字元後傳送出去,在接收端再換回換行字元。
這樣就會把問題避開了嗎?不行!不管你用的替代字元或字串有多複雜,一個最簡單的例子就會突破了!那就是,若有人在訊息中問你,你的替代字串是什麼?你回應的時候,不就又被抓來當換行字元了嗎?不過,這種情況真的很少,只有工程師自己會玩這種把戲啦!一般使用者不會想來搞死工程師的。

還有另外一種方法,是把整個訊息編碼(encode),例如 base64,編碼完沒有換行字元,就可以用來傳送,接收端接到再解碼(decode)。兩種方式端看效率以及應用情況來選擇。有時,兩端的程式並非同一個人或同一公司撰寫,因此實務才會有許多解法出現,但不脫字元取代及訊息編碼(encode)這兩大類。

沒有留言:

張貼留言