web-dev-qa-db-ja.com

継続的に実行するように設計されたプログラム(シリアルCOMポートでデータを変換)を終了するにはどうすればよいですか?

問題ステートメント

私は、シリアルCOM1を介して受信するバイナリデータを取得するC#コンソールプログラムを作成しています。各バイトをASCII hexに変換し、シリアルCOM2を介してそれらのHEX文字を出力します。

このプログラムをコマンドシェルで継続的に実行するだけでなく、正常に終了したい(COMポートなどのシステムリソースが解放されるように)。問題は、インバウンド/アウトバウンドのシリアルデータストリームにタイムアウトがないことです(プログラムを一度に数週間から数か月間実行したい)。では、ユーザーがプログラムを終了させたいときに、そのようなプログラムはどのように終了するのでしょうか。

接続先および切断先の機能は、ほとんどのターミナルエミュレータの標準機能であり、開発者がこのようなソリューションを実装する方法を知りたいと思っていました。

初期ソリューション

  1. プログラムにテキストファイルを読み取らせ、そこから「終了」などのコマンドを認識させます。ユーザーはテキストファイルを作成し、「quit」と書き込むだけで、アプリケーションが次にファイルの読み取りに取り掛かると、アプリケーションは終了することがわかります。私は古いUIを作成することを非難されるので、このソリューションは好きではありません。
  2. アプリケーションに3番目のCOMポートから読み取り、データストリームをコマンドとして処理させます。 ReadBufferに「quit」が見つかると終了します。
  3. 上記のプログラムをプロセスとして呼び出す2つ目のプログラム(プロセス)を作成します。次に、別のコンソールウィンドウで、2番目のプロセスにstdinからのユーザーI/Oを処理させます。ユーザーが「終了」と入力すると、2番目のプロセスが最初のプロセスを強制終了します。 (私は複数のプロセスで作業したことがないので、どの関数呼び出しまたはライブラリを見ればよいのかわかりません。
  4. プログラムをマルチスレッド化します。バイトで読み取るための実行スレッド、変換を実行するスレッド、変換されたファイルを書き出すスレッド、およびstdinからの入力を処理するスレッドを用意します。

コメント

時間をどのように投資すればよいかわかりません。現在、(4)を検討しています。

1
Minh Tran

explicitマルチスレッド化が必要であることを示唆する問題ステートメントには何もありません。 C#アプリケーションについて私が知らないのは、クロスプラットフォーム用に設計されたNet Coreアプリを作成しているかどうかです。これにより、使用できるオプションが制限される可能性があります。

Windowsのみ

記事 here を使用して、PInvokeを使用してSetConsoleCtrlHandler(...) Win32コールバックに登録します。このコールバックは、通常のコンソールアプリを閉じるイベント(Ctrl + C、中断、コンソールを閉じる、ログオフ、シャットダウン)をアプリが受け取ったかどうかを通知します。これにより、予期しないクローズをより適切に処理できます。

Windows Service を作成して、誰かがログインしていなくてもアプリケーションを実行できるようにすることができます。これには、サービスコントロールパネルを使用してアプリを起動/停止できるという利点があります。

クロスプラットフォーム

Linux/MacおよびWindowsを処理する必要がある場合、PInvokeを使用しても意味がありません。これはプラットフォーム固有であるためです。ただし、Apache Tomcat開発者に触発されたハイブリッドアプローチを採用できます。

彼らは別のTCPポートに制御インターフェースを作成しました。これにより、外部ツールがシャットダウン、再起動などの制御メッセージを送信できるようになります。Windowsの場合、開始を処理するWindowsサービスがありました。コンソールアプリ(TomcatはJavaベースのWebサーバー)であり、シャットダウンするときに適切な制御メッセージを送信します。Linux/ Macの場合、デーモン/サービスシステムに結び付けられたものと本質的に同じことをしたスクリプト。

個人的な経験

Windowsサービスで制御される別のコンソールデータ処理アプリを作成しました。この特定のデータ処理アプリを使用して、センサーを監視し、いくつかの複雑な計算を実行したため、問題を特定できました。データ処理アプリは、結果を準リアルタイム監視UIに送信しました。アプリは、マシンが動作する限り、停止することなく動作する必要がありました。データ処理アプリを制御するためだけに存在するWindowsサービスを作成することで、予期しない理由で古いインスタンスが停止した場合に、新しいインスタンスを簡単に起動できます。アプリのメモリ使用量やその他の正常性の基準を監視することもできます。

コンソールアプリで行った処理の1つは、正常にシャットダウンされなかったインスタンスによって消費されている残りのリソースがないことを確認することでした。それは現実には起こりませんでしたが、このプロセスの重要性は私たちにそのケースのために設計させました。

制御プロトコル

UDPに基づく単純な制御プロトコルを使用できます。 C#のソケットAPIには非同期の読み取り/書き込みがあります。そのため、明示的なマルチスレッドは必要ありません。その多くはあなたのために処理されます。

メッセージのフォーマットを決めるだけです。制御プログラムを使用する場合は、実行中のプロセスへの参照を保持して、プロセスの状態を監視し、実行中かどうかを判断できます。便利なコマンド:

  • ハングアップ-今すぐシャットダウンできます
  • リセット-元の状態に戻ります(つまり、ポートを閉じて再度開きます)
  • ハートビート-プロセスをリモートで管理する必要がある場合
2
Berin Loritsch

同等のSIGTERMプラットフォームを探し、それを処理するだけです。

Linuxでは、COMポートは単なる別のファイル記述子であり、別のプロセスに渡したり、プログラムが閉じたときに閉じたり(とにかく)するなど、あらゆる種類の奇妙なことを行うことができるため、Linuxの状況は非常に単純です。

他のプラットフォームでは、プログラムが突然終了したときにリソースが解放されない可能性があります RS#232を管理するための確立されたアプローチをC#でテストできます

さまざまな設定で、メインプロセスを監視するクラッシュハンドラープロセスがあり、それを再起動したり、エラーログを送信したりできますが、これはそれほど役に立ちません

それ以外、

  • オプション1および3:COMポートはログに記録される「終了」シーケンスを純粋に送信できます
  • オプション2は通常FTPです(個別のデータ/制御接続)
  • オプション4(オプション2と同様)はMTであり、実際には役に立たない

全体として、 仮想シリアルポートドライバー を作成しているようです

1
Silviu-Marian