Проблема в вашем коде, а не в 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
). Комбинация AByteCount = -1
и AReadUtilDisconnect = False
является особым случаем, когда длина кодируется непосредственно в потоковой передаче. Это в основном используется (но не ограничивается), когда отправитель вызывает IOHandler.Write(TStream)
с параметром AWriteByteCount
, установленным в значение True (по умолчанию это False).
При работе с нетекстовыми данными всегда полезно посылать длину данных впереди фактических данных, когда это возможно. Оптимизирует операции чтения.
Различные комбинации параметров ReadStream () работают по следующей логике:
AByteCount = -1, AReadUtilDisconnect = False: читать 4/8 байтов, интерпретировать как длину, а затем продолжать чтение, пока эта длина не будет получена.
AByteCount <-1, AReadUtilDisconnect = False: предположим, что AReadUntilDisconnect имеет значение True и продолжает считывать до отключения. </p>
AByteCount> -1, AReadUtilDisconnect = False: предварительно измерьте целевой TStream и продолжайте чтение, пока не будет получено число байтов AByteCount.
AByteCount <= -1, AReadUtilDisconnect = True: держать чтение до отключения. </p>
AByteCount> -1, AReadUtilDisconnect = True: предварительно измерьте целевой TStream и продолжайте чтение до отключения.
В зависимости от типа данных, которые клиент фактически отправляет на сервер, есть вероятность, что ReadStream()
, вероятно, не лучший выбор для чтения этих данных. В IOHandler доступно много разных методов чтения. Например, если клиент отправляет текст с разделителями (особенно если он отправляется с IOHandler.WriteLn()
), тогда ReadLn()
является лучшим выбором.