您的代碼試圖讀取InputBuffer
中的任意數據塊,並希望它們是完整有效的字符串。它是這樣做的,沒有ANY考慮你正在接收什麼樣的數據。這是多層次的災難處方。
您已連接到Telnet服務器,但使用的是TIdTCPClient
,而不是直接使用TIdTelnet
,所以你MUST手動解碼所接收任何遠程登錄序列BEFORE然後可以處理任何剩餘的字符串數據。查看TIdTelnet
的源代碼。有很多解碼邏輯發生在OnDataAvailable
事件觸發之前。所有Telnet序列數據都在內部處理,然後OnDataAvailable
事件提供解碼後剩餘的任何非Telnet數據。
一旦你進行了Telnet解碼處理,你必須注意的另一個問題是TEncoding.UTF8
只處理正確編碼的COMPLETE UTF-8序列。如果遇到嚴重編碼的序列,或者更重要的是遇到不完整的序列,則返回一個空白字符串。這已經被報告爲一個錯誤(參見QC#79042)。
CheckForDataOnSource()
將插入的任何原始字節存儲在那一刻到InputBuffer
中。 InputBufferAsString()
提取InputBuffer
在那一刻的任何原始字節,並嘗試使用指定的編碼對它們進行解碼。當您撥打InputBufferAsString()
時,InputBuffer
中的原始字節很可能並不總是包含COMPLETE UTF-8序列。機會有時InputBuffer
中的最後一個序列仍然在等待字節到達套接字,直到下一次調用CheckForDataOnSource()
纔會被讀取。這可以解釋爲什麼你的CheckText()
函數在使用TEncoding.UTF8
時收到空白字符串。
您應該使用IndyUTF8Encoding()
來代替(Indy使用自己的UTF-8編碼器/解碼器來避免TEncoding.UTF8
中的解碼錯誤)。至少,你不會得到空白字符串,但是當UTF-8序列跨越多個CheckForDataOnSource()
調用(不完整的UTF-8序列將被轉換爲?
字符)時,仍然可能會丟失數據。僅僅因爲這個原因,在這種情況下你不應該使用InputBufferAsString()
(即使TEncoding.UTF8
確實工作正常)。爲了正確地處理這個問題,你應該:
1)手動掃描通過InputBuffer
,計算有多少字節構成COMPLETE UTF-8只序列,然後傳遞到計數或InputBuffer.Extract()
TIdIOHandler.ReadString()
。任何剩餘的字節將在下一次保留在InputBuffer
中。爲了達到這個目的,你將不得不無條件地撥打第一個InputBufferIsEmpty()
電話,並且只需撥打CheckForDataOnSource()
,這樣即使你已經有一些字節,你也總是檢查更多字節。
2)改爲使用TIdIOHandler.ReadChar()
,完全擺脫InputBufferIsEmpty()
和CheckForDataOnSource()
的呼叫。缺點是如果UTF-8序列解碼爲UTF-16代理對,則會丟失數據。 ReadChar()
可以解碼替代品,但它不能返回對中的第二個字符(我已經開始爲未來版本的Indy返回String
而不是Char
,因此可以返回完整的代理對)處理新的ReadChar()
重載。
我可以通過刪除InputbufferAsString中的Encoding類型來解決這個問題。但是接收的文本包含UTF8文本,並且在我的程序顯示中我有「YX'Y Z)X'X1X(X1 [X.YX/X1X'YX'X1X/Z)Y [X /: Z) YYY X9X(YX1:「text :-(,請幫我 – SadeghAlavizadeh 2012-01-06 18:03:41
一個問題,爲什麼你不使用TidTelnet?這顯然是由telnet控制字符造成的... – whosrdaddy 2012-01-06 18:14:17
因爲idTelnet不支持UTF8,我也想做一些處理可能會在顯示前改變它 – SadeghAlavizadeh 2012-01-06 20:15:37