3

TCPサーバーから一度に1つの接続のみを許可したい。バックログの長さをゼロにせずにlistenを使用する方法を教えてください。

コード(下記)を使用していますが、2つのクライアントを1つずつ起動すると、両方が接続されます。私はwinsock2でVC++を使用しています。

listen(m_socket、-1);

バックログとしてゼロを渡すことも機能していません。

返信を待っています。

よろしく、
immi

4

4 に答える 4

7

実際にアプリケーションをWinsock2のみを使用するように制限できる場合は、その条件付き受け入れメカニズムを使用できます。

SOCKET sd = socket(...);
listen(sd, ...);
DWORD nTrue = 1;
setsockopt(sd, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, (char*)&nTrue, sizeof(nTrue));

これにより、接続バックログスペースが使用可能である限り、着信SYNパケットにSYN-ACK応答を自動的に送信しないようにスタックの動作が変更されます。代わりに、プログラムは接続を通常どおり受け入れる必要があるというシグナルを受け取ります-select()、WSAEventSelect()、WSAAsyncSelect()...-次に、accept()の代わりにWSAAccept()を呼び出します。

sockaddr_in sin;
WSAAccept(sd, (sockaddr*)&sin, sizeof(sin), ConditionalAcceptChecker, 0);

関数ConditionalAcceptChecker()を記述して、着信接続情報を確認し、接続を受け入れるかどうかを決定します。あなたの場合、あなたCF_REJECTがすでに接続を処理している限り、あなたはただ戻ることができます。

繰り返しになりますが、このメカニズムはWinsock 2に固有のものであることに注意してください。移植可能な動作が必要な場合は、プログラムがすでに接続されている間にリスニングソケットを閉じるという他の投稿のアドバイスの方が適しています。

于 2009-10-15T12:42:21.017 に答える
2

これは必要な接続数であるため、バックログを1に設定できます。

ただし、AFAIKには、キューサイズに関する厳格な保証はありません(このドキュメントによると、BSDでは1.5 *バックログになるとのことです)。

私見ですが、制限を超えて接続を受け入れないようにすることで、接続数を手動で制御したほうがよいでしょう。

于 2009-10-15T08:08:46.960 に答える
2

私はaccept一度だけ言うでしょう。サーバー上で一度に1つのクライアントのみが必要な場合は、1つのスレッドのみを使用して処理を実行することもできます。バックログは、システムによって処理される保留中の接続の量のみを制限し(最初の受け入れ後にキューは再び空になるため、次のクライアントはバックログに入ります)、接続の量は制限しません。

于 2009-10-15T08:29:33.760 に答える
2

これは、リッスンバックログの目的ではありません。

リッスンバックログは、保留中の接続に使用されるキューに影響を与えます。これにより、TCPスタックは、保留中の接続をキューに入れて受け入れることができます。

やりたいことを行うには、許可している1つの接続を受け入れてから、リスニングソケットを閉じる必要があります。単一のクライアントでの作業が終了したら、リスニングソケットを再作成して、新しい接続をリッスンできます。これにより、複数のクライアントが接続するのを防ぐことができますが、実際に接続を実行して「一度に1つずつ」接続を受け入れていることをクライアントが知る方法はありません。接続に成功したクライアントを除くすべてのクライアントは、あなたがそこにいないと思います。

リスニングソケットを開いたままにしてすべての接続を受け入れる方がおそらく良い設計ですが、「1つの」アクティブな接続を取得したら、単に受け入れてから、アプリケーションレベルのメッセージをクライアントに送信して、これ以上接続を受け入れることができないことを通知します。それはできません。新しい接続を閉じるだけです。

于 2009-10-15T11:02:20.367 に答える