2011-11-30 12 views
6

私の仕事は、TCPで接続された2台のコンピュータ間でプレイされる2人のプレーヤーのゲームを実装することです。必要条件の1つは、勝者だけが選択肢を再び与えられるかどうかを指定することです。サーバーが勝ち、それ以上プレイしないことを決定した場合、クライアントはサーバーとして再起動し、新しい接続を受け入れる必要があります。SO_REUSEADDRでbind()が失敗する

私のアプローチ: 、(クライアントモードでの)ゲームLOSTもし近い数sockfdと別のものを再作成します。 setsockoptを使用してSO_REUSEADDRを使用して再バインドを許可し、次にbindを呼び出します。

int yes = 1; 
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) 
{ 
    perror("setsockopt"); 
} 

if (bind(sockfd, (struct sockaddr*)&svr, sizeof(svr)) == -1) 
{ 
    perror("server: bind"); 
} 

でも、「アドレスは既に使用中です」というエラーが表示されます。私はソケットを作り直す前に150秒間スリープ状態にしましたが、この方法は機能します。

注:私は、同じPC上でこれをテストしています。リンクされた2台のPCで動作するかもしれませんが、同じPC上で動作させる必要があります。助けてください。

+2

コード(特に 'setsockopt()'の部分)を表示してください。 –

+4

クライアントコードでサーバー側(リスニングソケット)を再作成する前に正しく閉じていますか? Linuxシステムでは、 "netstat -tlp"は、それを受信するために開かれたTCPポートを保持しているものを特定する必要があります... – BRFennPocock

+0

同じマシン上で同じ{address、portnum}をbind()しようとしましたか?何が起こると思いますか? – wildplasser

答えて

2

あなたが同じシステム上でこれを実行しているので、あなたは競合状態を持っているように、それが聞こえます。クライアントはサーバが閉じられる直前にソケットをbind()にしようとしています(サーバとクライアントの両方がソケットにSO_REUSEADDRを設定していると仮定します)。

リスニングソケットを閉じた後、サーバがクライアントに通知することを可能にする何らかのハンドシェイクを実装する必要があります。最後の試合でアクティブソケットを閉じる前に、リスニングソケットを閉じる必要がありますか?このソケットオプションを設定する

+0

はい、ソケットが閉じられる前に1秒の遅延があり、再バインドを試みたときに遅延がありませんでした。今は完璧に機能します! :) – tecfreak

1

SO_REUSEADDRだけあなたが同時により特定のアドレスに結合することを可能にする、つまり最初のサーバは、(すべてのインタフェース)とその後のサーバが異なる特定のインターフェイスアドレスをリッスンINADDR_ANYで待機します。親サーバープロセスが終了を言うと、再び開始します - TCPソケットをリスニングすると、使用中に保たれている接続を受け入れますが、リスニングソケット自体が閉じて再度開いたときに

2つ目のシナリオです。あなたがbind(2)を呼び出す前に、あなたがに必要どちらの場合も

常には、リスニングソケットにSO_REUSEADDRオプションを設定します。

+0

これは他の方法ですか? 私は両方の呼び出しの前にSO_REUSEADDRを使用しています。 – tecfreak

+0

ほとんどの場合、このオプションは、閉じたソケットがTIME_WAIT状態のときに特定のポートで待機しているサーバーを再起動するときに1〜2分待機するのを避けるために使用されます。 –

+0

はい、それは私の2番目のポイントです。 –

0

は、ローカルアドレスの再利用を可能にします。閉じられていても解放されていないポートにバインドしようとすると問題が発生した場合(TIME_WAITで定義されているように最大2分かかる場合があります)。 SO_REUSEADDRソケットオプションを適用して、すぐにリソースを解放し、TIME_WAIT状態を回避します。 0 =使用不可、1 =使用可能。すでにポートにバインドされたアクティブリスニングソケットがある場合を除き

は、他のソケットがこのポートに()に結合することができます。これにより、クラッシュ後にサーバーを再起動しようとすると、「Address already in use」エラーメッセージが表示される可能性があります。

関連する問題