Linuxでソケットを使用してチャットクライアントを作成しましたが、接続を完全に破棄したいです。コードの関連部分は次のとおりです。
int sock, connected, bytes_recieved , true = 1, pid;
char send_data [1024] , recv_data[1024];
struct sockaddr_in server_addr,client_addr;
int sin_size;
label:
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Socket");
exit(1);
}
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) == -1)
{
perror("Setsockopt");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(3128);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero),8);
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))== -1)
{
perror("Unable to bind");
exit(1);
}
if (listen(sock, 5) == -1)
{
perror("Listen");
exit(1);
}
printf("\nTCPServer Waiting for client on port 3128");
fflush(stdout);
connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size);
//necessary code
close(sock);
goto label;
しかし、close(sock)は接続を完全に閉じないようです。これは、「ラベル」に移動した後、コードが終了してエラーメッセージが表示されるためです。
Unable to bind: Address already in use
つまり、接続は再び発生していません。問題は何ですか?前もって感謝します。
編集:私が実際に欲しいのは、接続を破棄した後に最初からスクリプトを実行すると、新しいプログラムとして実行されるはずです。どうすればできますか?
close
呼び出しは、TCPソケットが閉じられました。プロセスで使用できなくなります。ただし、カーネルは一定期間(TIME_WAIT、2MLSなど)のリソースを保持できます。
SO_REUSEADDRを設定すると、バインディングの問題が解消されます。
したがって、true
を呼び出すときは、setsockopt
の値が実際にゼロ以外であることを確認してください(オーバーフローのバグによって上書きされる可能性があります)。
true = 1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int))
コードにはpid
変数があります。 fork
(接続処理プロセスの開始用)を使用する場合は、それを必要としないプロセスでもsock
を閉じる必要があります。
最初に名前を付けるため、同じものに同じ名前を付けます。
サーバ側:
listen()
に渡されたソケットはaccept()
に渡され、リスニングソケットを呼び出しましょう。 accept()
によって返されたソケットは、受け入れられたソケットを呼び出しましょう。
クライアント側:
connect()
に渡されたソケットは、接続/接続されたソケットを呼び出しましょう。
あなたの問題について:
accept()
ed接続を終了するには受け入れられたソケットを閉じる(接続と呼ぶもの)最初に shutdown()
を使用してから close ()
。 accept()
への呼び出しの直前に新しい接続ループを受け入れるには、しないbind()
およびlisten()
を経由します。
connect()
が返された後に発行されたpendingaccept()
を削除する場合にのみ、リスニングソケットをシャットダウンして閉じます。
接続されたソケットを閉じるのを忘れたため、接続はまだアクティブです。リスニングソケットを閉じても、接続されているソケットは自動的に閉じられません。
//necessary code
close(connected); // <---- add this line
close(sock);
goto label;
EADDRINUSEを取得している理由はわかりません。コードはLinuxとMac OSの両方で正常に機能しました。
shutdown(2) システムコールを使用する必要があります。