从TCP套接字读取所有可用字节(未知字节数)

时间:2018-11-01 07:26:57

标签: sockets c++builder indy indy10 rad-studio

我在使用印第TIdTCPClient时遇到问题。 每当套接字上有可用数据时,我都想调用一个函数。为此,我有一个线程调用IdTCPClient->Socket->Readable(100)。 函数本身看起来像这样:

TMemoryStream *mStream = new TMemoryStream;
int len = 0;
try
{
    if(!Form1->IdTCPClient2->Connected())
        Form1->IdTCPClient2->Connect();
    mStream->Position = 0;
    do
    {
        Form1->IdTCPClient2->Socket->ReadStream(mStream, 1);
    }
    while(Form1->IdTCPClient2->Socket->Readable(100));

    len = mStream->Position;
    mStream->Position = 0;
    mStream->Read(Buffer, len);
}catch(Exception &Ex) {
    Form1->DisplaySSH->Lines->Add(Ex.Message);
    Form1->DisplaySSH->GoToTextEnd();
}
delete mStream;

它不会直接在线程内调用,但是线程会触发一个事件,该事件正在调用此函数。这意味着我两次使用Readable(100),而没有在betwee中读取数据。 因此,由于我不知道必须读取多少个字节,我以为我可以读取一个字节,因此请检查是否有更多可用字节,然后再读取另一个字节。 这里的问题是do while循环不会循环,它只会运行一次。 我猜测Readable并不能完全满足我的需要。 还有其他方法可以接收套接字中可用的所有字节吗?

1 个答案:

答案 0 :(得分:0)

在这种情况下,您不应该直接使用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()将等待直到{{ 1}}套接字接收任何新字节的间隔) 1

ReadTimeout

1:确保您使用的是Indy 10的最新快照。在2016年10月6日之前,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(); } 中有一个逻辑错误,而ReadBytes()没有在检查套接字中的新字节之前,请不要考虑AByteCount=-1