Delphi 如何确定套接字缓冲区中是否接收到所有数据?

Delphi 如何确定套接字缓冲区中是否接收到所有数据?,delphi,sockets,Delphi,Sockets,是否可以确定TServerSocket接收缓冲区中是否包含所有数据?协议就是这样 可以是已定义的结束标记。e、 g.HTTP中的CRLF 包含请求长度的标头 无法确定OnRead是否已完成读取,因为根据定义,没有结束。这意味着您不应该只发送没有特殊信息的二进制数据。例如,您可以先发送字节数(例如,4字节无符号整数),然后发送希望发送的字节 在接收器端,您首先读取,比方说,4个字节,现在您知道可以预期的字节数 如果要从服务器上的客户端读取数据,典型的方法是使用缓冲字符串(每个客户端套接字)和解析

是否可以确定
TServerSocket
接收缓冲区中是否包含所有数据?

协议就是这样

  • 可以是已定义的结束标记。e、 g.HTTP中的CRLF
  • 包含请求长度的标头

无法确定OnRead是否已完成读取,因为根据定义,没有结束。这意味着您不应该只发送没有特殊信息的二进制数据。例如,您可以先发送字节数(例如,4字节无符号整数),然后发送希望发送的字节


在接收器端,您首先读取,比方说,4个字节,现在您知道可以预期的字节数

如果要从服务器上的客户端读取数据,典型的方法是使用缓冲字符串(每个客户端套接字)和解析该字符串的循环。例如,我假设您创建一个对象来包装每个服务器/客户端套接字。在这个对象中,创建一个名为
Buffer
的字符串。无论何时从客户机接收数据,都将新数据追加到此字符串的末尾。然后,一个单独的进程(线程)可以解析这个字符串并检查完整的数据包。然而,读取数据包大小的方法完全取决于您

无法保证服务器在收到按发送顺序发送的数据时会触发事件。客户机可以向服务器发送4个数据包,服务器只为所有数据触发一个事件,或者客户机可以发送1个数据包,服务器为部分数据触发两个事件。根据套接字通信的性质,您有责任持续读取输入的完整数据

阿尔扎伊马尔的答案是你需要做什么。假设一个完整的数据包是如下所示的字符串:

这是一些字符串。

当解析这样的字符串时,使用除名器是有风险的。因此,取而代之的是,获取该字符串的大小,并在数据包上加上前缀,在该大小和数据之间只加一个去离子器。由于上面的字符串长度为20个字符,因此实际数据包应如下所示:

20:这是一些字符串。


…其中冒号(:)是大小和数据之间的除数。首先,你们要检查以确保除沫器存在。如果是这样,那么将所有内容复制到它。如果它是一个有效的数字,则意味着您需要从缓冲区中读取那么多字符。接下来,检查缓冲区是否有那么多可用数据。如果是这样,那么从缓冲区抓取数据。请记住仅在必要时从缓冲区中删除数据-如果您愿意,我可以提供更详细的代码示例。

为什么要使用非常过时的技术?
TServerSocket
TClientSocket
被降级,并且仅为向后兼容而存在。此外,你需要一个更具体的日志。是的,在掌握Delphi 6/7的过程中,我读到TTcpClient/Server是他们的替代品,但我发现很难使用它们-u-(包括Indy的一个)根据我的经验,Indy和Synapse更容易使用,我希望我能及时发现上面的打字错误,以便更正它……
TTcpClient/Server
是Borland在D6中为Kylix支持而尝试的跨平台套接字实现。Kylix已经死了,尽管这些组件仍然存在,但它们已经被Indy所取代。不,我的意思是,我怎么才能确定被触发的OnRead是最后一个呢?这可能是不可能的,我想,我并没有问过如何确定数据标记的结尾或类似的东西…@0x90这是不可能的。OnRead事件可以使用另一个数据包再次触发。这使得TServerSocket比Indy或Synapse更难处理,在Indy或Synapse中,您的代码要求库读取到终止符或已知数据长度(或直到发生错误/超时)。使用TServerSocket/TClientSocket,不会将“逻辑连接的”数据分离到OnRead事件调用中。@0x90:您必须跟踪正在实现的任何协议的状态。当您获得一个
OnRead
事件时,最好读取所有可用字节并将它们附加到您选择的缓冲区的末尾,然后您可以根据需要解析缓冲区,使用协议状态机了解缓冲区中的内容。只解析缓冲区中已完成的消息,并将缓冲区中剩余的字节留待以后的
OnRead
事件完成。这就是我已经在做的,使用Remmy的示例代码:但是,由于OnRead触发多次。。。我想确定什么时候是最后一次,这样我就可以一次读完所有的东西。这不是办法。操作系统决定何时再给你送一口蛋糕。OnRead将读取操作系统提供给您的内容并对其进行缓冲。换句话说:你必须收集它并做出反应。例如,当您收到“已宣布”字节的最后一部分时,您可以处理它们。@0x90:alzaimar是正确的。当您获得一个
OnRead
事件时,您必须读取套接字上可用的所有内容并将其缓冲到某个地方。然后,您可以根据您正在实现的任何协议,解析缓冲区以查看它是否包含完整的消息。如果发现已完成的消息,请将其从缓冲区中删除并根据需要进行处理,然后在缓冲区不再包含已完成的消息时再次重复。保留缓冲区中仍然存在的未完成字节,以便以后
OnRead
事件可以向其追加新字节。对收到的每个
OnRead
事件重复解析。