答案 0 :(得分:6)
问题出在您的代码中,而不是ReadStream()
。它按照设计行事。
它接受3个输入参数:
procedure ReadStream(AStream: TStream; AByteCount: TIdStreamSize = -1; AReadUntilDisconnect: Boolean = False); virtual;
您只为第一个参数提供值,因此其他两个参数使用默认值。
当AByteCount
参数设置为-1且AReadUntilDisconnect
参数设置为False时,ReadStream()
设计为假设接收的前4个字节(或8个字节,如果IOHandler.LargeStream
属性设置为True)是发送数据的长度,之后是实际数据。这就是为ReadStream()
调用ReadLongInt()
的原因。这不仅会告诉ReadStream()
何时停止读取,而且还允许ReadStream()
预先调整目标TStream的大小,以便在接收数据之前更好地进行内存管理。
如果客户端实际上没有在其数据之前发送4字节(或8字节)长度值,那么ReadStream()
仍然会将实际数据的起始字节解释为长度。这通常(但并非总是如此,取决于数据)导致ReadLongInt()
(或ReadInt64()
)返回一个大整数值,这会导致ReadStream()
期望大量数据将永远不会实际到达,从而无限制地阻止读取(或者直到发生超时,如果IOHandler.ReadTimeout
属性设置为非无限超时)。
为了有效地使用ReadStream()
,它需要知道何时停止阅读,或者通过提前告知预期有多少数据(即:AByteCount >= 0
),或者要求发送者发送数据后断开连接(即:AReadUtilDisconnect = True
)。 {(1}}和AByteCount = -1
的组合是一种特殊情况,当长度直接在流媒体中编码时。当发件人调用AReadUtilDisconnect = False
并将IOHandler.Write(TStream)
参数设置为True(默认情况下为False)时,主要使用(但不限于此)。
在处理非文本数据时,尽可能在实际数据之前发送数据长度始终是个好主意。它优化了阅读操作。
ReadStream()的不同参数组合符合以下逻辑:
AByteCount = -1,AReadUtilDisconnect = False:读取4/8字节,解释为长度,然后继续读取,直到收到该长度。
AByteCount< -1,AReadUtilDisconnect = False:假设AReadUntilDisconnect为True并继续读取,直到断开连接。
AByteCount> -1,AReadUtilDisconnect = False:预先调整目标TStream的大小并继续读取,直到收到AByteCount字节数。
AByteCount< = -1,AReadUtilDisconnect = True:继续阅读,直到断开连接。
AByteCount> -1,AReadUtilDisconnect = True:预先调整目标TStream的大小并继续读取,直到断开连接。
根据客户端实际发送到服务器的数据类型,AWriteByteCount
可能不是读取该数据的最佳选择。 IOHandler有许多不同类型的阅读方法。例如,如果客户端正在发送带分隔符的文本(特别是如果它与ReadStream()
一起发送),那么IOHandler.WriteLn()
是更好的选择。