繁体   English   中英

TIdTCPServer OnExecute 多次触发

[英]TIdTCPServer OnExecute fires multiple times

我有一个应用程序,它从另一个应用程序接收 TCP 套接字连接,处理通过套接字流式传输的内容,根据接收到的数据构建请求,使用 TIdHTTP 将请求发送到外部服务器,处理响应,然后发送一个确认回到 tcp 客户端。

procedure TMyClass.TCPExecute(AContext: TIdContext);
var
  s: AnsiString;
begin
  s := TransferTCPBytesToString(AContext.Connection.IOHandler);
  // test string for terminating characters
  if Pos(#28#13, s) > 0 then
  begin
  //********PROBLEM: THIS WILL BE CALLED MULTIPLE TIMES 
  //********WITH THE SAME COMPLETE DATA STREAM CONTENT!
    BuildAndSendExternalRequest(s);
    AContext.Connection.IOHandler.InputBuffer.Clear;
    // send the response back to tcp client
    WriteTCPResponse(AContext.Connection.IOHandler);
  end;
end;

function TMyClass.TransferTCPBytesToString(AnIOHandler: TIdIOHandler): AnsiString;
begin
  if AnIOHandler.InputBufferIsEmpty then
    Exit;
  // read message from tcp client connection
  AnIOHandler.ReadBytes(FTCPBytes, AnIOHandler.InputBuffer.Size, True);
  SetLength(Result, Length(FTCPBytes));
  // copy message bytes to string
  Move(FTCPBytes[0], Result[1], Length(FTCPBytes));
end;

procedure TMyClass.WriteTCPResponse(AnIOHandler: TIdIOHandler);
var
  bytes: TBytes;
begin
  // FTCPBytes contains data from tcp client
  // bytes will contain processed response from external server
  BuildACK(FTCPBytes,bytes);
  // FTCPBytes now contains ACK data
  AnIOHandler.WriteDirect(FTCPBytes, Length(FTCPBytes));
end;

请求/响应周期成功完成; 发送回 tcp 客户端请求者的响应是正确的,进程按预期执行和完成。

但是,由于 OnExecute 事件使用相同的数据多次触发,因此会接收、构建、发送、确认两个请求。

在查看 tcp 客户端应用程序上的日志时,日志仅显示正在发送的一个请求。 不知道这里发生了什么。 但是我需要确保请求/响应周期是 1-1,而不是 1-很多!

谢谢。

OnExecute 事件多次触发...

它应该是,因为它是一个循环事件。 只要连接处于活动状态,循环就会运行。 OnExecute事件处理程序中的代码负责决定在每次循环迭代中发生的事情。

理想的情况是事件处理程序从客户端接收 1 条消息,将 1 个响应发送回客户端,然后退出,以便下一次循环迭代准备处理下一个请求/响应对。

根据您的描述,您正在尝试这样做,但显示的代码处理得不是很好。 最值得注意的是,该代码没有考虑 TCP 的字节流性质。 它不区分一个传入的消息和另一个。 它只是将整个IOHandler.InputBuffer内容按IOHandler.InputBuffer转储到AnsiString (为什么是AnsiString ?),如果AnsiString恰好包含分隔符#28#13那么您正在处理整个AnsiString ,然后将其丢弃,丢失任何内容在分隔符之后接收(即下一条消息的一部分)。 如果AnsiString不包含分隔符,那么您仍然会丢弃AnsiString ,从而在分隔符到达之前丢失当前消息的所有数据。

如果您的所有消息都由#28#13分隔,那么我建议您使用IOHandler.ReadLn()IOHandler.WaitFor()方法正确读取每条消息。

此外,您正在为输入和输出重新使用相同的FTCPBytes成员,这本身是错误的,但如果您有多个客户端连接,您也不会为其提供任何并发访问保护。

话虽如此,请尝试更像这样的事情:

procedure TMyClass.TCPConnect(AContext: TIdContext);
begin
  AContext.Connection.IOHandler.DefStringEncoding := IndyTextEncoding_8Bit;
end;

procedure TMyClass.TCPExecute(AContext: TIdContext);
var
  s: String;
  response: TIdBytes:
begin
  s := TransferTCPBytesToString(AContext.Connection.IOHandler);
  BuildAndSendExternalRequest(s, response);
  // send the response back to tcp client
  WriteTCPResponse(AContext.Connection.IOHandler, response);
end;

function TMyClass.TransferTCPBytesToString(AnIOHandler: TIdIOHandler): String;
begin
  // read message from tcp client connection
  Result := AnIOHandler.ReadLn(#28#13);
  or:
  Result := AnIOHandler.WaitFor(#28#13);
end;

procedure TMyClass.BuildAndSendExternalRequest(const Msg: String; var Response: TIdBytes);
begin
  // send Msg to external server as needed...
  // store response bytes in Response...
end;

procedure TMyClass.WriteTCPResponse(AnIOHandler: TIdIOHandler; const Response: TIdBytes);
var
  bytes: TIdBytes;
begin
  // Response contains processed response from external server
  BuildACK(bytes, Response);
  // bytes now contains ACK data
  AnIOHandler.Write(bytes);
end;

...具有相同的数据

鉴于您显示的代码,这是不可能的。 要将呼叫IOHandler.ReadBytes()TransferTCPBytesToString()是阅读并丢弃在所有字节IOHandler.InputBuffer ,所以没有办法相同字节仍然可以在该缓冲区时TransferTCPBytesToString()在稍后的时间再次被调用。 o,您可以一遍又一遍地看到相同数据的唯一方法是客户端是否一遍又一遍地发送相同的数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM