2

私はまだ C ソケット プログラミングに慣れていませんが、いくつかの簡単なクライアント プログラムとサーバー プログラムを作成することができました。TCP接続をリッスンするサーバーをプログラミングしています。その義務は、クライアントの要求に応答し、クライアントが特別なバイトシーケンスを送信したとき(またはもちろん切断したとき)に通信を閉じます。

無限ループ内で関数を使用してサーバーのコーディングを開始しましたaccept()。サーバーはクライアントを待機し、accept() でそれを処理し、すべてを実行し、最後にソケット記述子を close() して、再び受け入れを待って戻ります。新しいクライアント。

一度に 1 つのクライアントにサービスを提供したいので、listen 関数を次のように呼び出しました。listen(mysocket, 1);

すべてうまくいきましたが、新しい問題が発生しました。上で説明したサーバー部分は別のスレッド (スレッド #2 と呼びましょう) で実行され、メイン スレッド (スレッド #1) はそれを終了するように伝えることができなければなりません。次に、グローバル変数を作成しました。この変数が (スレッド #1 によって) 1 に設定されている場合、スレッド #2 は終了する必要があります。問題は、関数が呼び出されたときにスレッド #2 がスタックしaccept()、グローバル変数を定期的にチェックできないことです。

その関数のタイムアウト値が明らかに必要でした。「受け入れる接続がない場合は、グローバル変数の値を確認し、0 に設定されている場合は新しい接続を待ち続け、1 に設定されている場合は終了します」。

そのとき、解決策をグーグルで検索したところ、select()関数が必要なことを実行することがわかりました。少し違いますがfd_set、FD_* マクロを初めて発見しました。サーバー部分を変更してselect()関数で動作するようにしましたが、すべてがうまく機能しますが、ここで最後の問題が発生します。これは私が解決できない問題です。この方法でリッスン関数を呼び出した場合:listen(socket, 1);ただし、サーバーは引き続き複数の接続を受け入れて同時に処理します。これは依存しますかselect()fd_set で動作しますか? Web で見つけたいくつかの例を使用しています。接続が受け入れられると、他のすべてのセットに含まれる新しいソケット記述子が作成されます。1 つのクライアントだけの接続を受け入れたいのですが、接続しているクライアントにサービスを提供する必要があるかどうかを認識する簡単なコードを書きましたが、サーバー側で接続を切断する方法はありますか? close()関数を使用してソケット記述子を閉じる必要があることはわかっていますが、使用するときselect()に fd_set を操作していて、それらを閉じるために何をすべきか本当にわかりません。または、セット内のソケット記述子の数を制限する方法はありますか? FD_SETSIZE マクロを見つけましたが、それを機能させることができず、問題が解決するかどうかさえわかりません。

お時間をいただきありがとうございます!

4

3 に答える 3

5

このlisten()関数には、拒否される前に保留できる着信要求の数を決定する引数backlogがあります。これは、OS 実装が呼び出しで指定した以上のものをサポートできるように、慎重に表現されています。バックログされた接続の正確な数を制御できない場合があります。listen()

一度に 1 つのクライアントのみをサポートする必要がある場合は、2 番目の接続を受け入れますが、新しいクライアントに現在接続が利用できないことを伝えてから、新しい接続を閉じます。これには、接続が利用できない理由をクライアントに伝える機会があるという利点もあります。

于 2012-07-08T22:00:23.407 に答える
0

fd_set に listen() ソケットを入れることもできます。(すでにこれを行っている場合、あなたの質問からはわかりません)リッスンソケットが読み取り可能であることを選択が示している場合は、リッスンソケットでacceptを呼び出すことができます。accept は正確に 1 つの fd を返します。返された fd を fd_set に入れることもできます。スレッドはこれと多かれ少なかれ直交しています。(システムコールはアトミックです)、もちろん、物事を台無しにすることができます。

listen の backlog パラメータは、多かれ少なかれ無関係です。システムが同時に維持する必要がある初期ソケットの数を指定するだけです(新しい fd を返すリッスンによって示されるように、ソケットが使用可能になる前であっても、接続の構築はリソースを使用します)。初期接続は、新しいソケット fd として生まれます。

getdtablesize() マクロは昔からの残りです。最新の実装では、getrlimit() に基づいています。

FD_SETSIZE の根本的な問題は、fd_set が割り当て可能な左辺値でなければならないことです。したがって、固定サイズにする必要があります。(おそらく構造体内の配列です) 固定サイズの構造体を避けるには、select() の代わりに poll() を使用できます (または複数のより小さい fd_sets を使用します ;-)

于 2012-07-08T22:09:18.440 に答える
-1

Windows API を使用している場合は、クリティカル セクションを試すことができます。

于 2012-07-08T21:59:20.117 に答える