Delphi Indy IdTCPServer 和 IdTCPClient。读写控制字符和文本

Delphi Indy IdTCPServer and IdTCPClient. read and write control characters and text

Delphi XE3,印地 10.5.9.0

我正在创建计算机和仪器之间的接口。该仪器使用 ASTM 协议。

我已经成功地在服务器和客户端之间来回发送基于文本的消息。我已经能够将控制字符发送到服务器并读取它们。经过 3 天的搜索,我还没有弄明白的是如何编写和读取混合了控制字符和文本的消息。

我发送的 ASTM 协议消息需要控制字符和文本,如下行所示。尖括号中的所有内容都是控制字符。写帖子是不是我运行哪里出问题了。这是在阅读它时,因为我将同时收到文本和控制字符。我下面的代码是我如何读取控制字符。我如何判断何时获取字符是否是控制字符以及何时是同一字符串中的控制字符和文本字符?感谢雷米·勒博 (Remy Lebeau) 和他在本网站上的帖子让我走到了这里。他谈到了如何使用缓冲区,但我不知道如何读取包含控制字符和文本字符的缓冲区。

<STX>3O|1|G-13-00017||^^^HPV|R||||||N||||||||||||||O<CR><ETX>D3<CR><LF>

我已将以下代码添加到我的服务器组件 OnConnect 事件中,该事件应该允许我发送控制字符...

...
AContext.Connection.IOHandler.DefStringEncoding := TIdTextEncoding.UTF8;
...

我的服务器 OnExecute 事件...

procedure TTasksForm.IdTCPServer1Execute(AContext: TIdContext);
var
  lastline : WideString;
  lastcmd :  WideString ;
  lastbyte : Byte ;
begin 

  ServerTrafficMemo.Lines.Add('OnExecute') ;

  lastline := '' ;
  lastcmd := '' ;

  lastbyte := (AContext.Connection.IOHandler.ReadByte) ;

  if lastbyte = Byte(5) then
  begin

    lastcmd := '<ENQ>' ;

    ServerTrafficMemo.Lines.Add(lastcmd) ;

    AContext.Connection.IOHandler.WriteLn(lastcmd + ' received') ;

  end;

end;

I couldn't tell how to read a buffer that contained control characters and text characters

这个协议无疑是使用ASCII字符串。十进制 32 以下的任何字符都将是控制字符。那些 32 及以上的将是数据字符。看 http://ascii-table.com/ascii.php

将其作为字节处理效果很好。也可以使用ansistring,就是ASCII加上前127个字符。在这种情况下,我会避免使用 UTF(any) 并坚持使用 byte 或 ansistring。您需要在字符级别控制消息,这些字符是每个字符 8 位,没有转义。

还有see the first example, in the first answer here:

目前唯一的控制字符是 STXETX,它们都小于 32,所以 ASCII 和 UTF-8 都可以很好地处理它们。或者,您可以使用 Indy 自己内置的 8 位编码来代替。

对于这种类型的数据,Indy 有几种 种不同的方法来读取它。由于大部分数据是文本数据,并且控制字符仅用作帧定界符,因此最简单的方法是使用带有显式终止符的 IOHandler.ReadLn()IOHandler.WaitFor()

当然还有其他的选择,比如直接从IOHandler.InputBuffer中读取字节(我觉得这种情况有点大材小用),用InputBuffer.IndexOf()方法知道有多少要读取的字节数。

此外,TIdTCPServer 是一个多线程组件,其事件在工作线程中触发,但您的代码直接访问 UI,这不是线程安全的。您必须与 UI 线程同步。

你也不应该 WideString。请改用 (Unicode)String

尝试这样的事情:

procedure TTasksForm.IdTCPServer1Connect (AContext: TIdContext);
begin AContext.Connection.IOHandler.DefStringEncoding := Indy8BitEncoding;
end;

procedure TTasksForm.IdTCPServer1Execute(AContext: TIdContext);
var
  lastline : string;
  lastcmd :  string ;
  lastbyte : Byte ;
begin
  TThread.Synchronize(nil,
    procedure
    begin
      ServerTrafficMemo.Lines.Add('OnExecute') ;
    end
  );

  lastbyte := (AContext.Connection.IOHandler.ReadByte);

  if lastbyte =  then
  begin
    lastcmd := '<ENQ>' ;
    TThread.Synchronize(nil,
      procedure
      begin
        ServerTrafficMemo.Lines.Add(lastcmd) ;
      end
    );
  end
  else if lastbyte =  then
  begin
    lastline := #2 + AContext.Connection.IOHandler.ReadLn(#3) + #3;
    lastline := lastline + AContext.Connection.IOHandler.ReadLn(#13#10) + #13#10;
    { or:
    lastline := #2 + AContext.Connection.IOHandler.WaitFor(#3, true, true);
    lastline := lastline + AContext.Connection.IOHandler.WaitFor(#13#10, true, true);
    }
    lastcmd := '<STX>' ;
    TThread.Synchronize(nil,
      procedure
      begin
        ServerTrafficMemo.Lines.Add(lastcmd) ;
      end
    );
  end;
  AContext.Connection.IOHandler.WriteLn(lastcmd + ' received') ;
end;