c++builder - 在 C++Builder 中使用 Indy TIdTCPServer 读取分隔数据包
问题描述
我有一个微处理器设备想要连接到 TCP 服务器,然后在每次输入状态发生变化时发送一个令牌。标记的形式"AS9=0;"
为 noCR
或LF
。每个令牌都在一个长度为 6 的数据包中发送。为了使我的项目正常工作,我希望允许连接打开、接收数据并使用它,而无需等待另一个打包或关闭连接。
C++Builder 附带的套接字组件集是 Indy 10。它代表了惊人的工作量。但是,所有这些工作都在 Pascal 中,对我没有多大用处。可以说文档很困难。理想情况下,我想逐包读取数据。我可以确定没有办法做到这一点。我试过这个AllData()
方法。虽然它可以工作,但它会等到连接关闭才能读出数据。这对我不可用。我也试过这个ReadLn()
方法。一旦遇到LF
. 它也没有用,因为我的数据不包含LF
s。
到目前为止,我的代码如下所示:
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 ";"
?
解决方案
如果您查看 的声明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"));
}
//---------------------------------------
推荐阅读
- javascript - Python Selenium:execute_script 是否能够等待 javascript 内容加载?
- c# - Telerik Grid,详细视图 - 如何指定路线值
- python - 如何从 databricks 显示和下载 pptx 文件?
- java - 将 YYYY-MM-DDThh:mm:ssTZD 格式日期字符串转换为本地时间
- sql-server - 数据仓库:找出 sql server 表的哪些行发生了变化,以方便数据仓库
- sql - Oracle 中枢轴的中位数
- regex - 使用正则表达式确定用户是否有两对扑克手
- angular - Angular 7 反应式 - 动态添加到 FormArray 的下拉菜单过早显示错误
- curl - Google Drive API 范围:为什么我只能访问一个?
- php - 自定义字段和事件