首页 > 解决方案 > 在 C++Builder 中使用 Indy TIdTCPServer 读取分隔数据包

问题描述

我有一个微处理器设备想要连接到 TCP 服务器,然后在每次输入状态发生变化时发送一个令牌。标记的形式"AS9=0;"为 noCRLF。每个令牌都在一个长度为 6 的数据包中发送。为了使我的项目正常工作,我希望允许连接打开、接收数据并使用它,而无需等待另一个打包或关闭连接。

C++Builder 附带的套接字组件集是 Indy 10。它代表了惊人的工作量。但是,所有这些工作都在 Pascal 中,对我没有多大用处。可以说文档很困难。理想情况下,我想逐包读取数据。我可以确定没有办法做到这一点。我试过这个AllData()方法。虽然它可以工作,但它会等到连接关闭才能读出数据。这对我不可用。我也试过这个ReadLn()方法。一旦遇到LF. 它也没有用,因为我的数据不包含LFs。

到目前为止,我的代码如下所示:

void __fastcall TForm1::IdTCPServer1Execute(TIdContext *AContext)
{
    UnicodeString mystring;
    RichEdit1->Lines->Add(" * ");
    mystring = AContext->Connection->IOHandler->AllData();
    RichEdit1->Lines->Add(mystring + " *** ");
}
//-----------------------------------
void __fastcall TForm1::IdTCPServer1Disconnect(TIdContext *AContext)
{
    RichEdit1->Lines->Add("Disconnected. . .  \r\n");
}
//--------------------------------------
void __fastcall TForm1::IdTCPServer1Connect(TIdContext *AContext)
{
    RichEdit1->Lines->Add("Connected. . .  \r\n");
}
//---------------------------------------

正如我所提到的,上面的代码将显示所有内容,但只有在连接关闭时才会显示。鉴于所有这些,我有两个问题。首先,如何在数据包进来后立即获取数据?其次,对于ReadLn(),如何将行分隔符从 a 更改LF为 a ";"

标签: c++builderindy

解决方案


如果您查看 的声明TIdIOHandler::ReadLn(),您会发现它有一个可选ATerminator参数:

String __fastcall ReadLn(_di_IIdTextEncoding AByteEncoding  = NULL);

String __fastcall ReadLn(String ATerminator, _di_IIdTextEncoding AByteEncoding);

String __fastcall ReadLn(String ATerminator, int ATimeout = IdTimeoutDefault, int AMaxLineLength = -1, _di_IIdTextEncoding AByteEncoding = NULL);

如果您不指定终止符,则默认为LF(包括CRLF)。您可以根据需要指定不同的终止符,例如:

void __fastcall TForm1::IdTCPServer1Execute(TIdContext *AContext)
{
    ...
    String mystring = AContext->Connection->IOHandler->ReadLn(_D(";"));
    ...
}

在单独的说明中,TIdTCPServer是一个多线程组件。它的事件在工作线程的上下文中触发。因此,在访问 UI 控件时,您必须与主 UI 线程同步,例如:

void __fastcall TForm1::AddLine(const String &S)
{
    #if defined(__clang__)
    TThread::Synchronize(nullptr, [&, this](){ RichEdit1->Lines->Add(S); });
    #else
    struct TAddLineSync
    {
        String Line;
        TAddLineSync(const String &ALine) : Line(ALine) {}
        void __fastcall AddLine() { Form1->RichEdit1->Lines->Add(Line); }
    };
    TAddLineSync sync(S);
    TThread::Synchronize(NULL, &sync.AddLine);
    #endif
}
//-----------------------------------
void __fastcall TForm1::IdTCPServer1Execute(TIdContext *AContext)
{
    AddLine(_D(" * "));
    String mystring = AContext->Connection->IOHandler->ReadLn(_D(";"));
    AddLine(mystring + _D(" *** "));
}
//-----------------------------------
void __fastcall TForm1::IdTCPServer1Disconnect(TIdContext *AContext)
{
    AddLine(_D("Disconnected. . .  \r\n"));
}
//--------------------------------------
void __fastcall TForm1::IdTCPServer1Connect(TIdContext *AContext)
{
    AddLine(_D("Connected. . .  \r\n"));
}
//---------------------------------------

推荐阅读