sockets - 从 TCP Socket 读取所有可用字节(未知字节数)
问题描述
我在使用 Indy 时遇到问题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)
了两次,中间没有读取数据。因此,由于我不知道必须读取多少字节,所以我认为我可以读取一个字节,检查是否有更多可用字节,然后再读取另一个字节。这里的问题是 do while 循环不循环,它只运行一次。我猜 Readable 并不完全符合我的需要。有没有其他方法可以接收 Socket 中可用的所有字节?
解决方案
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 的最新快照。在 2016 年 10 月 6 日之前,在检查套接字是否有新字节之前没有考虑ReadBytes()
到逻辑错误。AByteCount=-1
InputBuffer
推荐阅读
- react-native-android - 如何从 react-native 代码中禁用 Android 默认的“Touchable onPress”声音?
- c++ - 对一个顶点缓冲对象 (VBO) 中的多个立方体重复 UV?
- python - Wagtail 自定义 PageChooserPanel 页面资源管理器视图
- css - Yii2:如何更改 Select2 小部件的字体系列
- docker - 如何将文件复制到 Docker 卷并将该卷与 docker-compose 一起使用
- java - 接下来在 hs_err_pid###.log 文件中查看什么?
- jenkins - 来自 Jenkins 管道的 HTTP 请求,带有代理身份验证和客户端证书
- python-3.x - 使用套接字的 Python3 OpenWeather API
- sql-server - GCloud,如何连接到 MSSQL 实例
- python - 如何使用 Numpy 更新初始数组