2009-03-24 10 views
8

私はLinuxソケットを使ってC++でクライアントとサーバーのペアを書いています。私はサーバーが接続を待ち受けるようにしたい。そして、あるクライアントが接続されている間、サーバーは接続しようとする他のクライアントを拒絶すべきである。一度に1つの接続だけを受け入れるTCPサーバーを作成するにはどうすればよいですか?

listen関数のバックログパラメータを0と1に設定して実装しようとしましたが、これらの値のどちらも機能していないようです。最初のクライアントは期待どおりに接続しますが、後続のクライアントは最初のクライアントの終了時にブロックされます。私にとって本当に混乱しているのは、サーバーへの接続をブロックしないことです。最初の読み取りでブロックします。

クライアントとサーバーの作成を開始するには、the code hereを使用しました。誰も私は、サーバーが1つだけのクライアント接続を受け入れるように変更する必要があることを知っていると、その後の接続の試行をドロップ?

答えて

7

接続を受け入れると、新しいソケットが作成されます。古いものは将来の接続を待ち受けるために使用されます。

一度に1つの接続のみを許可したいので、すでに接続を受け入れておき、すでに別の接続を処理していることを検出した場合は、新しい受け入れられたソケットを閉じることができます。

受け入れた直後に新しい受け入れられたソケットを閉じるのと比べて、あなたが探している正味の違いはありますか?クライアントは、ソケットを使用しようとすると直ちに(または直ちに読み取り呼び出しでサーバー上で待機している場合はすぐに)知り、最後のエラーでサーバーは接続をアクティブに閉じます。

+0

これを行うことができるかどうか確認するためにコードを変更しています。私はあなたに戻ってきます... –

+0

+1正確に私が提案しようとしていたものです。 –

+0

行く良い方法と思われます! Tks! – LeoPucciBr

4

fork()の後には、accept()の直後にしないでください。

この擬似Cコードは、一度に1クライアントのみを受け入れます。

while(1) { 
    listen() 
    accept() 
    *do something with the connection* 
    close() 
} 
+1

私はfork()しません。この例は、リクエストを処理するだけの単純なエコーサーバです。 –

3

最初の接続を受け入れると、接続を待機している元のソケットを閉じることができます。あなたが使っているソケットクラスがそれを可能にするかどうかはわかりません。

+0

それはアイデアですが、最初の処理が完了した後に新しい接続を受け入れるようにしたいと思います。 –

+0

@Billを使用して、再度接続を受け入れる準備ができたらソケットを再度開きます。 –

3

手作業で実装する必要があります。クライアントに接続して、すでに別のクライアントが接続されている場合は、サーバーからクライアントに切断メッセージを送信します。クライアントがこのメッセージを受け取った場合、それ自体は切断されます。

0

クライアントを制御できる場合は、ソケットを非ブロックにすることができます。この場合、エラーメッセージEINPROGRESSが返されます。

私はまだソケットを非ブロッキングに変更する方法を探しています。誰かがオフハンドを知っている場合は、自由に答えを編集してください。

0

新しい接続を受け入れて開始した後に、リスニングソケットが消滅するようにします。次に、その接続が完了したら、新しいリスニングソケットをスピンオフさせます。

 
TCP_DEFER_ACCEPT (since Linux 2.4) 
    Allows a listener to be awakened only when data arrives on the socket. 
    Takes an integer value (seconds), this can bound the maximum number of 
    attempts TCP will make to complete the connection. This option should 
    not be used in code intended to be portable. 

が、私はそれが接続しているクライアントがconnectにブロックしないこと、あなたが説明した効果につながると仮定しますが、上になります。

0

あなたのリスニングソケットにソケットオプションTCP_DEFER_ACCEPTセットを持っているかもしれませんその後のread。私は、オプションのデフォルトの設定だと、この動作を無効に設定すべきかに、しかし、ゼロの、おそらく値は試してみる価値があるかを正確にはわからない:

あなただけの1を許可したいので
int opt = 0; 
setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &opt, sizeof(opt)); 
+0

私は一度に1つの接続だけを許可することも考えています。私は上記の 'setsockopt'を使ってみました: ' int opt = 0; setsockopt(sock、IPPROTO_TCP、TCP_DEFER_ACCEPT、&opt、sizeof(opt)); ただし、動作しませんでした。だから私は 'opt'を1に設定して試しましたが、それでも動作しませんでした。 ここで 'sizeof(opt)'のチェックが必要ですか? –

1

一度に接続できる場合は、接続を受け入れるだけで、既に別のソケットを処理していることを検出した場合は、新しい受け入れられたソケットを閉じることができます。

私はそれが閉じられるべき聴取ソケットであるべきだと思います。 最初の接続が確立されたら、元のリスンソケットを閉じます。 その後、接続を確立することはできません。

最初の接続が終了したら、新しいソケットを作成してもう一度聞くことができます。

0

私が見る限り、正確に1つの接続を聞くことはできません。

Tcpには3方向ハンドシェイクが含まれます。最初のsynパケットが受信された後、カーネルはその待ち行列にその「接続」を入れ、syn/ackで応答し、最後のackを待ちます。これが受信されると、それは接続を待ち行列から受け入れ待ち行列に移動させ、accept()呼び出しを使用してアプリケーションによって取り上げることができる。 (詳細はhereをご覧ください)

Linuxでは、バックログ引数は受け入れキューのサイズのみを制限します。カーネルは引き続き3ウェイハンドシェイクの魔法を実行します。クライアントはsyn/ackを受け取り、最後のackで応答し、確立された接続を呼び出します。

唯一のオプションは、最初の接続を受け入れるとすぐにリスニングソケットをシャットダウンすることです。 (ただし、他の接続が既に利用可能になっている可能性があります)。または、他の接続をアクティブに受け入れ、すぐに閉じてクライアントに通知します。

最後に使用しているオプションは、すでに使用しているオプションです。サーバーが接続をキューに入れ、順番に処理するようにします。あなたのクライアントはその場合にブロックされます。

関連する問題