2016-04-23 11 views
1

Delphi XE3、Indy 10.5.9.0Delphi Indy IdTCPServerおよびIdTCPClient。読み取りと書き込みの制御文字とテキスト

私はコンピュータと計測器の間のインターフェイスを作成しています。機器はASTMプロトコルを使用します。

私は正常にサーバーとクライアントの間でテキストベースのメッセージをやりとりしました。私は制御文字をサーバに送り、それらを読むことができました。私が3日間の検索をしてもわからないことは、制御文字とテキストが混在したメッセージをどのように書いて読んでいくかです。

次のような制御文字とテキストが必要なASTMプロトコルメッセージを送信しています。山括弧内のすべてが制御文字です。メッセージを書くことは私が問題にぶつかるところではない。私はテキストと制御文字の両方を受け取るので、それを読むときです。私のコードは以下の通りです。どのようにキャラクターがコントロールキャラクターであるかどうか、コントロール文字列とテキストキャラクターの同じ文字列内のテキストであるかどうかを私はどのように知ることができますか?レミー・ルボーとこのサイトの彼のポストのおかげで私はどこにいるのか教えてくれました。彼はバッファの使い方について話しましたが、制御文字とテキスト文字を含むバッファを読み込む方法を教えていませんでした。

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

私は...

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; 
をOnExecuteイベントイベント

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

私のサーバー...私は制御文字を送信することを可能にすることになっているのOnConnectイベント私のサーバーコンポーネントに次のコードを追加しました

答えて

1

存在する唯一の制御文字は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 = $5 then 
    begin 
    lastcmd := '<ENQ>' ; 
    TThread.Synchronize(nil, 
     procedure 
     begin 
     ServerTrafficMemo.Lines.Add(lastcmd) ; 
     end 
    ); 
    end 
    else if lastbyte = $2 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; 
+0

うわー:

はこのような何かを試してみてください!私はこの記事のすべての良いものを消化しようとしています!なぜあなたは 'lastbyte ='行に$を、ReadLn行に#を使用していますか? –

+0

'lastbyte'はバイトです。 '$ 5'は数値で、' Byte(5) 'に相当し、ちょうどクリーナーです。 'ReadLn()'と 'WaitFor()'はバイトではなく文字列で動作します。 '#2'と'#3'は文字値( 'Char(2)'と 'Char(3)')です。 –

+0

readまたはreadlnを「タイムアウト」する方法はありますか? –

0

制御文字とテキスト文字を含むバッファの読み方を教えられませんでした

このプロトコルは間違いなくASCII文字列を使用しています。小数点以下32文字は制御文字になります。 32文字以上はデータ文字になります。 http://ascii-table.com/ascii.php

これをバイトとして扱うと問題はありません。 ASCIIと上位127文字のansistringも使用できます。このような状況では、私はUTF(any)を避け、バイトまたはansistringのいずれかを使用します。文字レベルでメッセージを制御する必要があります。これらの文字はエスケープなしの文字あたり8ビットです。またsee the first example, in the first answer here

は:

関連する問題