Sad*_*deh 3 delphi telnet indy tcpclient
我在下面的代码中遇到问题,idTCPClient用于从telnet服务器读取缓冲区:
procedure TForm2.ReadTimerTimer(Sender: TObject);
var
S: String;
begin
if IdTCPClient.IOHandler.InputBufferIsEmpty then
begin
IdTCPClient.IOHandler.CheckForDataOnSource(10);
if IdTCPClient.IOHandler.InputBufferIsEmpty then Exit;
end;
s := idTCPClient.IOHandler.InputBufferAsString(TEncoding.UTF8);
CheckText(S);
end;
Run Code Online (Sandbox Code Playgroud)
此过程每1000毫秒运行一次,当缓冲区调用CheckText值时.
此代码有效,但有时会将空缓冲区返回给CheckText.
有什么问题?
谢谢
您的代码正在尝试从中读取任意数据块,InputBuffer并期望它们是完整且有效的字符串.这不就是做这个的任何适合什么样的数据,您收到的考虑.这是多层次的灾难处方.
您已连接到Telnet服务器,但您TIdTCPClient直接使用而不是使用TIdTelnet,因此您必须手动解码在接收到任何剩余字符串数据之前接收的任何Telnet序列.查看源代码TIdTelnet.在OnDataAvailable触发事件之前会发生很多解码逻辑.所有Telnet序列数据都在内部处理,然后OnDataAvailable事件提供解码后留下的任何非Telnet数据.
一旦你接受了Telnet解码,你必须注意的另一个问题是TEncoding.UTF8只处理正确编码的COMPLETE UTF-8序列.如果它遇到编码错误的序列,或者更重要的是遇到不完整的序列,则整个解码失败并返回一个空白字符串.这已被报告为一个错误(参见QC#79042).
CheckForDataOnSource()店无论原始字节是在插座的那一刻到InputBuffer. InputBufferAsString()提取当时正在处理的任何原始字节InputBuffer ,并尝试使用指定的编码对其进行解码.很可能并且InputBuffer您调用时的原始字节可能InputBufferAsString()并不总是包含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()可以解码代理,但它不能返回对中的第二个字符(我已经开始处理新的ReadChar()重载,以便将来返回Indy String而不是返回Char完整的代理对可以返回).
| 归档时间: |
|
| 查看次数: |
4562 次 |
| 最近记录: |