Вы не должны использовать Readable()
непосредственно в этой ситуации. Этот вызов сообщает, имеются ли в ожидаемом сокете непрочитанные данные во внутреннем буфере ядра. Это не учитывает, что TIdIOHandler
может уже иметь непрочитанные данные в InputBuffer
, которые остались от предыдущей операции чтения.
Используйте метод TIdIOHandler::CheckForDataOnSource()
вместо TIdIOHandler::Readable()
:
TMemoryStream *mStream = new TMemoryStream;
try
{
if (!Form1->IdTCPClient2->Connected())
Form1->IdTCPClient2->Connect();
mStream->Position = 0;
do
{
if (Form1->IdTCPClient2->IOHander->InputBufferIsEmpty())
{
if (!Form1->IdTCPClient2->IOHander->CheckForDataOnSource(100))
break;
}
Form1->IdTCPClient2->IOHandler->ReadStream(mStream, Form1->IdTCPClient2->IOHandler->InputBuffer->Size, false);
/* alternatively:
Form1->IdTCPClient2->IOHandler->InputBuffer->ExtractToStream(mStream);
*/
}
while (true);
// use mStream as needed...
}
catch (const Exception &Ex) {
Form1->DisplaySSH->Lines->Add(Ex.Message);
Form1->DisplaySSH->GoToTextEnd();
}
delete mStream;
Или вы можете использовать TIdIOHandler::ReadBytes()
вместо TIdIOHandler::ReadStream()
. Если вы установите для параметра AByteCount
значение -1
, он вернет только те байты, которые доступны в данный момент (если InputBuffer
пусто, ReadBytes()
будет ожидать до интервала ReadTimeout
, пока сокет не получит новые байты) 1 :
try
{
if (!Form1->IdTCPClient2->Connected())
Form1->IdTCPClient2->Connect();
TIdBytes data;
do
{
if (Form1->IdTCPClient2->IOHander->InputBufferIsEmpty())
{
if (!Form1->IdTCPClient2->IOHander->CheckForDataOnSource(100))
break;
}
Form1->IdTCPClient2->IOHandler->ReadBytes(data, -1, true);
/* alternatively:
Form1->IdTCPClient2->IOHandler->InputBuffer->ExtractToBytes(data, -1, true);
*/
}
while (true);
// use data as needed...
}
catch (const Exception &Ex) {
Form1->DisplaySSH->Lines->Add(Ex.Message);
Form1->DisplaySSH->GoToTextEnd();
}
1: убедитесь, что вы используете актуальный снимок Indy 10. До 6 октября 2016 года в ReadBytes()
была логическая ошибка, когда AByteCount=-1
не принимал InputBuffer
перед проверкой сокета на наличие новых байтов.