gpt4 book ai didi

Delphi XE3、Indy TCPServer 和 TCPClient。发送和接收 CRLF 控制码

转载 作者:行者123 更新时间:2023-12-02 01:30:52 26 4
gpt4 key购买 nike

我在上一篇文章中得到了帮助,但出现了另一个问题,我不知道如何处理评论。

我需要知道如何在行尾使用 CRLF 来执行 WriteLn。我以为我正在发送一封,但相信我处理错误,因为它似乎没有结束。以下是其中一条消息的框架。这是消息的人类可读版本,通过用实际控制代码替换人类可读版本进行转换。

<STX>1H|\^~||||||||||P|1|20150724124402<CR><ETX>91<CR><LF>
<STX>2P|1|PP00015906|||Sox^White||19550506||||||<CR><ETX>56<CR><LF>
<STX>3O|1|G-13-00005||^^^CT/GC|R||||||N||||||||||||||O<CR><ETX>23<CR><LF>
<STX>4O|2|G-13-00005||^^^HPV^HPV|R||||||N||||||||||||||O<CR><ETX>F6<CR><LF>
<STX>5L|1|N<CR><ETX>DF<CR><LF>

我认为当我将消息从人类可读的“代码”转换为实际的控制代码时,我可能做错了什么。帧中间的控制代码似乎正常。这是可能不会超出的帧末尾的部分。

          // replace human readable codes with control codes
pantherastmframe := StringReplace(pantherastmframe, '<STX>', #2, [rfReplaceAll] ) ;
pantherastmframe := StringReplace(pantherastmframe, '<CR>', #13, [rfReplaceAll] ) ;
pantherastmframe := StringReplace(pantherastmframe, '<ETX>', #3, [rfReplaceAll] ) ;
pantherastmframe := StringReplace(pantherastmframe, '<LF>', #10, [rfReplaceAll] ) ;

我在客户端上使用以下代码来检查控制代码。

      MsgIn := PantherIdTCPClient.IOHandler.ReadLn ;

crlffound := 'False' ;

if Pos( #13#10, MsgIn) > 0 then
crlffound := 'True' ;

为了清楚起见,我提供了完整的代码。

OnConnect 代码。

procedure TTasksForm.IdTCPServer1Connect(AContext: TIdContext);
begin

AContext.Connection.IOHandler.DefStringEncoding := Indy8BitEncoding ;

ServerTrafficMemo.Lines.Add(FormatDateTime( 'yyyy-mm-dd hh:nn:ss.zzz', now ) +' OnConnect') ;

// connected message
AContext.Connection.IOHandler.WriteLn('Connected');

end;

OnDisconnect 代码。

procedure TTasksForm.IdTCPServer1Disconnect(AContext: TIdContext);
begin

ServerTrafficMemo.Lines.Add(FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', now) +
' OnDisconnect') ;
end;

这是 OnExecute 代码。

procedure TTasksForm.IdTCPServer1Execute(AContext: TIdContext);
var
lastline : String;
lastcmd : String ;
lastbyte : Byte ;
i : integer ;
pantherastmframe : string ;
begin

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

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

if lastbyte = $5 then // <ENQ>
begin

lastcmd := '<ENQ>' ;

TThread.Synchronize(nil,
procedure
begin
ServerTrafficMemo.Lines.Add( FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', now) +
' <= <ENQ>') ;
end );

AContext.Connection.IOHandler.Write(Byte(6)) ; // <ACK>

TThread.Synchronize(nil,
procedure
begin
ServerTrafficMemo.Lines.Add(FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', now) +
' => <ACK>') ;
end );

LastPantherByte := lastbyte ; // <ENQ>

end

else

if lastbyte = $4 then // <EOT>
begin

TThread.Synchronize(nil,
procedure
begin
ServerTrafficMemo.Lines.Add(FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', now) +
' <= <EOT>') ;
end );

// are there messages to transmit
if ConsolidatedASTMMessagesMemo.Lines.Count > 0 then
begin

// turn off panther timer
TThread.Synchronize(nil,
procedure
begin
PantherProcessTimer.Enabled := False ;
end );

TThread.Synchronize(nil,
procedure
begin
ServerTrafficMemo.Lines.Add(FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', now) +
' => <ENQ>') ;
end );

AContext.Connection.IOHandler.Write(Byte(5)) ; // <ENQ>

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

if lastbyte = $6 then // <ACK>
begin

lastcmd := '<ACK>' ;

TThread.Synchronize(nil,
procedure
begin
ServerTrafficMemo.Lines.Add( FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', now) +
' <= <ACK>') ;
end );

// transmit frames
for i := 0 to ConsolidatedASTMMessagesMemo.Lines.Count-1 do
begin


pantherastmframe := ConsolidatedASTMMessagesMemo.Lines[i] ;

TThread.Synchronize(nil,
procedure
begin
ServerTrafficMemo.Lines.Add(FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', now) +
' => ' + pantherastmframe) ;
end );

// replace human readable codes with control codes
pantherastmframe := StringReplace(pantherastmframe, '<STX>', #2, [rfReplaceAll] ) ;
pantherastmframe := StringReplace(pantherastmframe, '<CR>', #13, [rfReplaceAll] ) ;
pantherastmframe := StringReplace(pantherastmframe, '<ETX>', #3, [rfReplaceAll] ) ;
pantherastmframe := StringReplace(pantherastmframe, '<LF>', #10, [rfReplaceAll] ) ;

AContext.Connection.IOHandler.WriteLn(pantherastmframe) ;

// wait for <ACK>

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

if lastbyte = $6 then // <ACK>
begin

TThread.Synchronize(nil,
procedure
begin
ServerTrafficMemo.Lines.Add(FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', now) +
' <= <ACK>') ;
end );

end

else

if lastbyte = $21 then // <NAK>
begin

TThread.Synchronize(nil,
procedure
begin
ServerTrafficMemo.Lines.Add( FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', now) +
' <= <NAK>') ;
end );

end ;

end ; // transmit frames

TThread.Synchronize(nil,
procedure
begin
ServerTrafficMemo.Lines.Add( FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', now) +
' <= <EOT>') ;
end );

// tell panther you are done for now
AContext.Connection.IOHandler.WriteLn(#4) ; // <EOT>

LastPantherByte := lastbyte ; // <EOT>

ConsolidatedASTMMessagesMemo.Clear ;

end ;

// turn on panther timer
TThread.Synchronize(nil,
procedure
begin
PantherProcessTimer.Enabled := True ;
end );

end ;

end;

end;

最佳答案

WriteLn()确实发送了 CRLF在指定数据的末尾。真正的问题是你期待 ReadLn()包括CRLF在其输出中,但实际上没有。 ReadLn()等待指定的终止符(默认为 LF),然后从输出中删除终止符(如果使用的终止符为 LF 并且接收到 CRLF,则删除整个 CRLF)。您的代码没有考虑到这一点,例如:

MsgIn := PantherIdTCPClient.IOHandler.ReadLn + #13#10;
// or, if you do not actually need the CRLF in the output:
// MsgIn := PantherIdTCPClient.IOHandler.ReadLn;

// no need for checking Pos()...
crlffound := 'True';

请注意,如果您设置 IOHandler 的 ReadTimeout属性(property),或 ReadLnATimeout参数,设置为非无限超时,然后 ReadLn()将在超时时返回空白字符串并设置 ReadLnTimedOut属性设置为 True,而不是引发异常:

MsgIn := PantherIdTCPClient.IOHandler.ReadLn + #13#10;
if PantherIdTCPClient.IOHandler.ReadLnTimedOut then
begin
// do something...
end else
begin
crlffound := 'True';
// do something else...
end;

另请注意,默认情况下,ReadLn()将裸 LF 和 CRLF 同等地处理为行终止符。如果您只想专门处理 CRLF,可以在可选的 ATerminator 中指定 CRLF。参数:

ReadLn(#13#10)

综上所述,另一种选择是使用 WaitFor()而不是ReadLn()WaitFor()有一个可选的AInclusive您可以将参数设置为 True 以在输出中包含 CRLF。如果读取超时,它也会引发异常:

MsgIn := PantherIdTCPClient.IOHandler.WaitFor(#13#10, True, True);
// no need for Pos() here...
crlffound := 'True';

OnConnect code.
OnDisconnect code.

您的事件处理程序中有线程不安全的代码。事件处理程序在 TIdTCPServer 内的工作线程中运行,但是他们直接访问UI,这是不安全的。访问 ServerTrafficMemo 时,您必须与主 UI 线程同步。 ,就像您在 OnExecute 中所做的那样事件处理程序(尽管您没有同步对 ConsolidatedASTMMessagesMemo 的访问,但您必须这样做)。

关于Delphi XE3、Indy TCPServer 和 TCPClient。发送和接收 CRLF 控制码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36961140/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com