6

職場では、Modbus スレーブ デバイスの一部として TCP サーバーを実装する任務を負っています。ここでスタック交換とインターネット全般 (優れたhttp://beej.us/guide/bgnet/を含む) の両方で多くのことを読みましたが、設計上の問題に苦しんでいます。要約すると、私のデバイスは 2 つの接続のみを受け入れることができ、各接続で着信 modbus 要求が発生します。これをメイン コントローラー ループで処理し、成功または失敗の状態で応答する必要があります。これを実装する方法について、次のアイデアがあります。

  1. 接続の作成、バインド、リッスン、受け入れを行うリスナー スレッドを作成し、新しい pthread を生成して着信データをリッスンし、アイドル タイムアウト期間後に接続を閉じます。アクティブなスレッドの数が現在 2 の場合、新しい接続は即座に閉じられ、2 つだけが許可されるようになります。

  2. リスナー スレッドから新しいスレッドを生成しないでください。代わりに select() を使用して、アクティブな接続で着信接続要求と着信 modbus 接続を検出します (Beejs ガイドのアプローチと同様)。

  3. 2 つのリスナー スレッドを作成し、それぞれが accept() 呼び出しでブロックできるソケット (同じ IP とポート番号) を作成し、ソケット fd を閉じて接続を処理します。ここで、ブロック読み取りを使用して処理できる最大 2 つの接続のみが許可されると (おそらく単純に) 想定しています。

私は長い間 C++ を使用してきましたが、Linux 開発に関してはかなりの初心者です。上記のアプローチのどれが最適か (もしあれば)、また、私の Linux の経験が浅いために、それらのいずれかが本当に悪いアイデアであるという提案があれば、本当に歓迎します。私は fork() を避けて pthreads に固執することに熱心です。着信 modbus 要求はキューに入れられ、定期的にメイン コントローラー ループから読み取られるからです。アドバイスをよろしくお願いします。

4

3 に答える 3

3

3 番目の方法は機能しません。ローカル アドレスにバインドできるのは 1 回だけです。

多くの処理を行う必要がない限り、おそらく2番目の代替手段を使用します。その場合、最初の代替手段と代替手段の組み合わせが役立つ場合があります。

私が考えている最初の 2 つの選択肢の組み合わせは、メイン スレッド (プログラムの開始時に常に存在するスレッド) に 2 つのワーカー スレッドを作成させてから、ブロッキングaccept呼び出しを行って新しい接続を待機させることです。新しい接続が到着したら、スレッドの 1 つに新しい接続での作業を開始し、ブロックに戻るように指示しacceptます。2 番目の接続が受け入れられると、その接続で動作するように他のスレッドに指示します。両方の接続が既に開いている場合は、一方の接続が閉じられるまで受け入れないか、新しい接続を待ってすぐに閉じます。

于 2012-06-12T09:22:12.717 に答える
2

あなたが提案するすべての設計オプションは、あまりオブジェクト指向ではなく、C++ よりも C を対象としています。作業でブーストを使用できる場合、Boost.Asio ライブラリは単純な (および複雑な) ソケット サーバーを作成するのに最適です。ほとんどすべての例を取り上げて、それを簡単に拡張して、2 つのアクティブな接続のみを許可し、他のすべての接続が開かれるとすぐに閉じることができます。

頭のてっぺんから、単純な HTTP サーバーを変更して、接続クラス (コンストラクターの inc、デストラクターの dec) に静的カウンターを保持し、新しいカウンターが作成されたときにカウントを確認して決定することで、これを行うことができます。接続を閉じるかどうか。接続クラスは、タイムアウトを追跡するために boost::asio::deadline_timer を取得することもできます。

これは、最初の設計の選択に最もよく似ています。ブーストはこれを 1 つのスレッドで実行し、バックグラウンドでselect()(通常はepoll()) に似た処理を実行します。しかし、これは「C++ の方法」であり、私の意見では、select()pthreadの s を使用するのが C の方法です。

于 2012-06-12T09:55:59.897 に答える
2

2 つの接続しか扱っていないため、接続ごとのスレッドはこの種のアプリケーションに最適です。数千の接続にスケールアップする必要がある場合は、ノンブロッキングまたは非同期 I/O を使用するオブジェクト指向のアプローチが適しています。2 つのリスナー スレッドは理にかなっています。accept fd を閉じる必要はありません。接続が完了したら、戻って承認してください。実際には、3 つのスレッドが受け入れをブロックするというバリエーションがあります。2 つのスレッドがアクティブに接続を処理している場合、3 番目のスレッドは新しく作成された接続をリセットします (またはデバイスに適したビジー応答を返します)。

3 つのスレッドすべてが受け入れ時にブロックされるようにするには、3 つのスレッドが起動して受け入れ/処理を行う前に、メイン スレッドでソケットを作成してバインドする必要があります。

Linux の pthreadsのman ページは、accept がスレッドセーフであることを示しています。(スレッドセーフ関数の下のセクションには、スレッドセーフではない関数がリストされています。図を参照してください。)

于 2012-06-12T09:22:15.493 に答える