30

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)は、接続を完全に破棄するようには見えません。これは、「label」に移動した後、コードが終了してエラーメッセージが表示されるためです。

Unable to bind: Address already in use

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

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

4

5 に答える 5

47

このclose呼び出しは、TCPソケットが閉じていることを示すだけです。プロセスでは使用できなくなりました。ただし、カーネルは一定期間リソースを保持している可能性があります(TIME_WAIT、2MLSなど)。

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

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

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

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

于 2012-05-18T10:37:58.347 に答える
8

最初に名前を付けるので、私たちは皆同じものに同じ名前を付けます。

サーバ側:

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

クライアント側:

接続/接続されconnect()たソケットを呼び出すために渡されたソケット。


あなたの問題について:

accept()ed接続を終了するには、オプションで最初にを使用し、次に。を使用して、受け入れられたソケット(接続と呼ばれるもの)を閉じます。shutdown()close ()

次に、への呼び出しの直前に新しい接続ループを受け入れるには、を何度も経由しないaccept()でください。bind()listen()

返された後に発行された保留中のを取り除きたい場合にのみ、リスニングソケットをシャットダウンして閉じます。 connect()accept()

于 2012-05-16T16:53:37.733 に答える
7

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

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

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

于 2012-05-18T06:05:20.147 に答える
0

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

于 2012-05-16T16:01:00.250 に答える
-2

ええと、相手がそれを確認したとき、または特定のタイムアウト後に接続が実際に閉じられるためです。これは通常の動作です...

編集:私は実際にあなたのコードをチェックしませんでしたが、他のユーザーのコメントから、あなたは何か間違ったことをしています...

于 2012-05-16T13:50:47.913 に答える