web-dev-qa-db-ja.com

エラー:ソケットをアドレスでバインドしているときにアドレスはすでに使用されていますが、ポート番号は「netstat」によって無料で表示されます

ポート番号_8000_でソケット(サーバーソケット)をバインドしようとしました。それは私のために働き、仕事をしました。コードの最後で、ソケットも閉じます。次の瞬間、コードを再度実行すると、アドレスがすでに使用されていることがわかります。エラー値の意味strerror(errno);を出力して、各ポイントでコードが適切に機能するかどうかを確認しました。ポートが空いているかどうかを確認するには、netstatを使用してチェックしましたが、ポート番号_8000_が空いていることがわかります。私には何度も起こりました。その後、さらに数秒間待機するたびに、再び動作を開始します。 C言語を使用しています。それで、彼は私のOSによるこの振る舞いの理由は何でしょうか。

さらに数秒後、コードを実行すると動作します。

_anirudh@anirudh-Aspire-5920:~/Desktop/testing$ Sudo ./a.out 
Socket Creation: Success
File open: Success
Socket Bind: Address already in use
Socket Listen: Address already in use
^C
anirudh@anirudh-Aspire-5920:~/Desktop/testing$ Sudo netstat -lntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1348/lighttpd   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      984/sshd        
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN      1131/cupsd      
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      1211/mysqld     
tcp6       0      0 :::22                   :::*                    LISTEN      984/sshd        
tcp6       0      0 ::1:631                 :::*                    LISTEN      1131/cupsd      
anirudh@anirudh-Aspire-5920:~/Desktop/testing$ Sudo ./a.out 
Socket Creation: Success
File open: Success
Socket Bind: Address already in use
Socket Listen: Address already in use
^C
anirudh@anirudh-Aspire-5920:~/Desktop/testing$ 
_
48
Durin

私も同じ問題に遭遇しました。これは、ソケットへの接続を閉じているが、ソケット自体を閉じていないためです。ソケットはTIME_WAIT状態に入ることができます(すべてのデータが送信されたことを確認するために、TCP配信を保証します)) および解放に最大4分かかります

または、本当に詳細な/技術的な説明については、 このリンクを確認してください

確かにうんざりするかもしれませんが、それを回避する方法はありません。バグではありません。

52
icfantv

質問がされてからしばらく経ちましたが、解決策を見つけることができました。

int sockfd;
int option = 1;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));

これにより、すぐに再利用できるソケットが設定されます。

これが「間違っている」場合は謝罪します。ソケットの経験があまりない

21
Supamee

次のようなnetstatを試してください:netstat -ntp-lなし。 TIME_WAIT状態のtcp接続が表示されます。

20
hipe

既に述べたように、ソケットはおそらくTIME_WAIT状態に入ります。この問題はThomas A. Finehere で説明されています。

要約すると、ソケットを閉じるプロセスは次の図に従います。

Socket closing process

Thomas言います:

上の図を見ると、リモートエンドが閉鎖を開始した場合、TIME_WAITを回避できることが明らかです。したがって、サーバーは最初にクライアントを閉じることで問題を回避できます。クライアントがいつ閉じるべきかを知るように、アプリケーションプロトコルを設計する必要があります。サーバーは、クライアントからのEOFに応答して安全に閉じることができますが、EOF多くの場合、サーバーが閉じる前に数秒待つだけで十分です。

SO_REUSEADDRの使用は、インターネットでは一般的に推奨されていますが、Thomasを追加します。

奇妙なことに、SO_REUSEADDRを使用すると、実際にはより困難な「既に使用されているアドレス」エラーにつながる可能性があります。 SO_REUSADDRは、TIME_WAITでスタックしているポートを使用することを許可しますが、そのポートを使用して、最後に接続した場所への接続を確立することはできません。何?ローカルポート1010を選択し、foobar.comポート300に接続し、ローカルで閉じて、そのポートをTIME_WAITのままにしておきます。ローカルポート1010をすぐに再利用して、foobar.comポート300以外のどこにでも接続できます。

6
Jezz

入力するだけ

unlink [SOCKET NAME]

端末では、エラーはもう存在しないはずです。

6
programmer

この質問に対するicfantvの答えでさえすでに完璧です、私はまだ私のテストでより多くの発見を持っています。

リスニングステータスのみのサーバーソケットとして、リスニングステータスのみで、クライアントサイドからのリクエストとデータの取得を受け入れますが、データ送信アクションはありません。停止した後でもサーバーを一度に再起動できました。ただし、サーバー側でクライアントへのデータ送信アクションが発生した場合、同じサービス(同じポート)の再起動で次のエラーが発生します:(アドレスは既に使用されています)。

これはTCP/IPの設計原理が原因だと思います。サーバーがクライアントにデータを送り返すとき、データ送信が成功することを確認する必要があります。これを行うには、OS(Linux)は、サーバーアプリケーションがこのソケットを閉じた場合でも接続を監視する必要があります。しかし、カーネルソケットデザイナーはこの問題を改善できると今でも信じています。

1
Clock ZHONG

私が受け取ったエラーは:

cockpit.socket: Failed to listen on sockets: Address already in use

私が発見した修正は:

  1. Selinuxを無効にする必要がありました
  2. / usr/lib/systemd/system/cockpitサービスで次の行を変更しました:

    #ExecStartPre=/usr/sbin/remotectl certificate --ensure --user=root --group=cockpit-ws --selinux-type=etc_t
    

    に:

    #ExecStartPre=/usr/sbin/remotectl certificate --ensure --user=root --group=cockpit-ws 
    

あなたが見ることができるように、私はselinuxに関する議論を取り出してから実行しました:

systemctl daemon-reload
systemctl start cockpit.service

それから私は閲覧しました:

自己署名証明書を受け入れ、コックピットに正常にログインし、正常に使用することができました。

これはすべてFedora25マシン上にあります。 90_90ポートは既にfirewall-cmdを使用して追加されていました

0
JamesAD-0

AF_UNIXの場合、call unlink(パス)を使用できます。 「サーバー」アプリのclose()ソケットの後

0
dr_begemot