2014-04-21 59 views
1

我使用gen_tcp通過TCP在Erlang接收消息。按照{packet, 4}選項的規定,通過使用4字節長的報頭將數據流分成數據包。這是我怎麼稱呼gen_tcp:listen/2如何處理Erlang中TCP流中數據包的錯誤長度標頭?

gen_tcp:listen(Port, [binary, inet, {active, once}, {packet, 4}]). 

正如你所看到的,我用的是{active, once}選項,這樣我可以毫不淹沒它取從工藝郵箱我的包。只要長度標題正確,此工作正常。如果不是,任何事情都可能發生。所以我想以某種方式處理錯誤包的可能性。

這有點棘手,因爲我實際上正在處理一個流。忽略錯誤的數據包會沒問題,但是我怎麼讓Erlang跳過這些數據包並識別下面的數據包?這個問題通常如何處理?

使用分隔符更好嗎?我已經看過gen_tcp的其他packet選項。尤其是以下幾點:

asn1 | cdr | sunrm | fcgi | tpkt | line 

唯一一個我真正理解的意思是line,但我不認爲這是一個不錯的選擇。我期待接收在Objective C中發送和構建的包,這是我不熟悉的,它包含許多不同類型的數據,不僅包含字符串。

回答

4

我不認爲你可以使用時跳過「不良」數據包{包,N}

主要原因是,什麼是壞的包?

任何4個字節可以表示大小,因此,如果有人送: 您好\ n

你實際上得到: 0x48656c6c 爲大小頭,說明框架:1214606444個字節長 之後的「o \ N」 然後你掛

您可以設置{PACKET_SIZE,1024}(或其他),讓你從分配1.2GB的‘你好’

不知道這會返回一個錯誤或丟棄插座。

由於消息在傳輸過程中被任意分開,因此TCP中的錯誤組幀可能無法恢復。

如果您不使用{packet,N},那麼您必須執行自己的分段控制,例如獲取文本行,您需要知道消息何時結束。

如果你控制客戶端/服務器協議,您可能需要使用{包,HTTP}或類似cowboy

一個更完全成熟,我們的解決方案然後,你必須在客戶端提交的HTTP請求(身體仍然可以通過二進制),並且框架處理對您的畸形的請求。

如果你需要一個雙通道directionaly,WebSockets的可能仍然是好的(假設你已經在目標下的WebSocket的LIB)

+0

感謝您的回覆,大衛。我想我會堅持長幀,並依靠正確實施的協議。我正在考慮一個解決方案,在'receive'子句中經過一段時間之後,套接字的緩衝區將被刷新,表明沒有收到數據包或者緩衝區中的下一個數據包是錯誤的,並讓客戶端重新發送消息。不過,我還沒有想出在主動模式下刷新套接字緩衝區的方法。我嘗試切換到「被動」模式並調用'recv/2',希望它能做到這一點。它沒有。 (爲什麼?) – Max

+0

如果您使用的是{packen,N},則無法刷新它。如果您自己實現了成幀,則始終可以在套接字讀取上超時。沖洗緩衝區永遠不是一個好的選擇,雖然...說你的超時時間是5秒,而你的客戶端發送3000字節。你的MTU大概是1500字節,所以你得到兩個1500字節的數據包。但是如果另一端掛起呢。假設它位於實時遷移的VMWare節點上,或者您有某種類型的GC暫停或某種情況。您只會刷新前1500個字節以獲得另一個1500字節的錯誤數據包。 –