2016-04-30 13 views
2

私は以前の投稿で助けられましたが、コメントを扱う方法がわからないという別の問題が出てきました。Delphi XE3、Indy TCPServerおよびTCPClient。

私は、行の最後にCRLFでWriteLnを行う方法を知る必要があります。私は1つを送っていると思ったが、それが終わっていないように私は間違ってそれを処理していると信じている。ここにメッセージの1つのフレームがあります。これは人間が読める形式のメッセージで、人間が読めるものを実際の制御コードに置き換えることによって変換されます。

<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> 

私は、実際の制御コードを人間が読める「コード」からのメッセージを変換するとき、私はおそらく何か間違ったことをやっていると仮定します。フレームの中央にある制御コードはOKになります。それは終わりではないかもしれないフレームの終わりです。

  // 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' ; 

わかりやすくするために、完全なコードを記載しました。

オンコネクトコード。

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 code。

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; 

答えて

1

WriteLn()は確かに指定されたデータの最後にCRLFを送信ありません。実際の問題は、にその出力に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財産、またはReadLnATimeoutパラメータを、設定した場合、その後ReadLn()がタイムアウトに空の文字列を返すことに注意してくださいそしてTrueにReadLnTimedOutプロパティを設定し、代わりに例外を発生させる:

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) 

、別のオプションはReadLn()の代わりにWaitFor()を使用することです。 WaitFor()にはオプションのAInclusiveパラメータがあり、Trueに設定してCRLFを出力に含めることができます。また、経過読み取りタイムアウト場合は例外が発生します:コードのOnConnect

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

を。
OnDisconnectコード。

イベントハンドラにスレッドセーフなコードが含まれています。イベントハンドラはTIdTCPServerのワーカースレッドで実行されますが、UIに直接アクセスしていますが、これは安全ではありません。 へのアクセスは同期していませんが、OnExecuteの場合と同様に、はServerTrafficMemoにアクセスすると、ServerTrafficMemoにアクセスするとメインUIスレッドと同期する必要があります。となります。

0

あなたがそのコードの両端を管理していて、それがデータ転送だと思うなら、RESTfulなことを学ぶのはあなた自身の責任です。コードをもっと柔軟にし、より洗練された抽象を書く強力な能力を与えます。それはより迅速な開発につながります。

関連する問題