web-dev-qa-db-ja.com

Cでソケット接続を完全に破壊する方法

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

つまり、接続は再び発生していません。問題は何ですか?前もって感謝します。

編集:私が実際に欲しいのは、接続を破棄した後に最初からスクリプトを実行すると、新しいプログラムとして実行されるはずです。どうすればできますか?

22
Harikrishnan

close呼び出しは、TCPソケットが閉じられました。プロセスで使用できなくなります。ただし、カーネルは一定期間(TIME_WAIT、2MLSなど)のリソースを保持できます。

SO_REUSEADDRを設定すると、バインディングの問題が解消されます。

したがって、trueを呼び出すときは、setsockoptの値が実際にゼロ以外であることを確認してください(オーバーフローのバグによって上書きされる可能性があります)。

true = 1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int))

コードにはpid変数があります。 fork(接続処理プロセスの開始用)を使用する場合は、それを必要としないプロセスでもsockを閉じる必要があります。

31
SKi

最初に名前を付けるため、同じものに同じ名前を付けます。

サーバ側:

listen()に渡されたソケットはaccept()に渡され、リスニングソケットを呼び出しましょう。 accept()によって返されたソケットは、受け入れられたソケットを呼び出しましょう。

クライアント側:

connect()に渡されたソケットは、接続/接続されたソケットを呼び出しましょう。


あなたの問題について:

accept() ed接続を終了するには受け入れられたソケットを閉じる(接続と呼ぶもの)最初に shutdown() を使用してから close ()accept()への呼び出しの直前に新しい接続ループを受け入れるには、しないbind()およびlisten()を経由します。

connect()が返された後に発行されたpendingaccept()を削除する場合にのみ、リスニングソケットをシャットダウンして閉じます。

6
alk

接続されたソケットを閉じるのを忘れたため、接続はまだアクティブです。リスニングソケットを閉じても、接続されているソケットは自動的に閉じられません。

//necessary code
close(connected);  // <---- add this line
close(sock);
goto label;

EADDRINUSEを取得している理由はわかりません。コードはLinuxとMac OSの両方で正常に機能しました。

4
enobufs

shutdown(2) システムコールを使用する必要があります。