him*_*elf 6 delphi indy indy10 idhttp
我有一个JSON-RPC服务,其中一个请求返回一个连续的JSON对象流.
即:
{id:'1'}
{id:'2'}
//30 minutes of no data
{id:'3'}
//...
Run Code Online (Sandbox Code Playgroud)
当然,没有内容长度,因为流是无穷无尽的.
我正在使用自定义TStream后代来接收和解析数据.但内部TIdHttp
缓冲数据并且RecvBufferSize
在收到字节之前不会将其传递给我.
这导致:
{id:'1'} //received
{id:'2'} //buffered by Indy but not received
//30 minutes of no data
{id:'3'} //this is where Indy commits {id:'2'} to me
Run Code Online (Sandbox Code Playgroud)
显然这不会做,因为30分钟前重要的信息应该在30分钟前送达.
我希望Indy能做套接字的工作:如果有可用数据则立即读取RecvBufferSize并立即返回.
我从2005年发现了这个讨论,其中一些可怜的灵魂试图向Indy开发者解释这个问题,但他们并不了解他.(阅读它;这是一个悲伤的景象)
无论如何,他通过编写自定义IOHandler后代来解决这个问题,但那是在2005年,也许今天有一些现成的解决方案?
虽然使用 TCP 流是一种选择,但最终我采用了编写自定义TIdIOHandlerStack
后代的原始解决方案。
动机是,使用 TIdHTTP,我知道什么不起作用,只需要修复它,而切换到较低级别的 TCP 意味着可能会出现新问题。
这是我正在使用的代码,我将在这里讨论关键点。
NewTIdStreamIoHandler
必须继承自TIdIOHandlerStack
.
需要重写两个函数:ReadBytes
和ReadStream
:
function TryReadBytes(var VBuffer: TIdBytes; AByteCount: Integer;
AAppend: Boolean = True): integer; virtual;
procedure ReadStream(AStream: TStream; AByteCount: TIdStreamSize = -1;
AReadUntilDisconnect: Boolean = False); override;
Run Code Online (Sandbox Code Playgroud)
两者都是经过修改的 Indy 函数,可以在 中找到IdIOHandler.TIdIOHandler
。该ReadBytes
子句while
必须替换为单个ReadFromSource()
请求,以便TryReadBytes
在一次性读取最多 AByteCount 字节后返回。
基于此,ReadStream
必须处理 AByteCount (>0, <0) 和 ReadUntilDisconnect (true, false) 的所有组合,以循环读取然后写入从套接字到达的数据流块。
请注意,ReadStream
如果套接字中只有部分请求的数据可用,即使在此流版本中也不需要提前终止。它只需立即将该部分写入流中,而不是将其缓存在 中FInputBuffer
,然后阻塞并等待下一部分数据。
归档时间: |
|
查看次数: |
2298 次 |
最近记录: |