8

Visual Studio Pro C ++でソケット(Winsock2)を作成して、接続(TCP)のポートをリッスンしました。完全に動作しますが、独自のスレッドで実行するようにしました。後で再起動することを期待して、シャットダウンできるようにしたいと思います。問題なくスレッドを終了できますが、そうしてもソケットが新しいクライアントを受け入れるのを止めることはありません(つまり、スレッドを閉じる前に行っていた受け入れにとどまります)。新しいクライアントを接続することはできますが、何も起こりません...それは受け入れるだけで、それだけです。私が欲しいのは、それがリッスンして受け入れるのを止めて、後で同じポートで再起動するように指示できるようにすることです。今すぐ再起動しようとすると、ポートがすでに使用されていることがわかります。

スレッドのリッスン機能は次のとおりです。

DWORD WINAPI ListeningThread(void* parameter){
TCPServer *server = (TCPServer*)parameter;

try{
    server = new TCPServer(listen_port);
}catch(char* err){
    cout<<"ERROR: "<<err<<endl;
    return -1;
}

int result = server->start_listening();
if(result < 0){
    cout<<"ERROR: WSA Err # "<<WSAGetLastError()<<endl;
    return result;
}
cout<<"LISTENING: "<<result<<endl<<endl;
while(true){
    TCPClientProtocol *cl= new TCPClientProtocol(server->waitAndAccept());
    HANDLE clientThread = CreateThread(0, 0, AcceptThread, cl, 0, 0);
    cout<<"Connection spawned."<<endl;
}

return 0;
}

TCPServerの関連機能は次のとおりです。

TCPServer::TCPServer(int port){
listening = false;
is_bound = false;

//setup WSA
int result = WSAStartup(MAKEWORD(2, 2), (LPWSADATA) &wsaData);
if(result < 0){
    throw "WSAStartup ERROR.";
    return;
}

//create the socket
result = (serverSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP));
if(result < 0){
    throw "Socket Connect ERROR.";
    return;
}

//bind socket to address/port
SOCKADDR_IN sin;
sin.sin_family = PF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = INADDR_ANY;

result = bind(serverSocket, (LPSOCKADDR) &sin, sizeof(sin));
if(result < 0){
    throw "Could not Bind socket - Make sure your selected PORT is available.";
    return;
}

is_bound = true;
}

int TCPServer::start_listening(){
int result = -1;
if(is_bound){
    //SOMAXCONN parameter (max) is a backlog:
    //  how many connections can be queued at any time.
    result = listen(serverSocket, SOMAXCONN);
    if(result >= 0)
        listening = true;
}
return result;
}

SOCKET TCPServer::waitAndAccept(){
if(listening)
    return accept(serverSocket, NULL, NULL);
else
    return NULL;
}

closesocket()とshutdown()の両方を試しましたが、どちらもエラーをスローしました。

お手数をおかけしますが、よろしくお願いいたします。

4

1 に答える 1

10

まず、SO_REUSEADDRリスニングを再開できるようにサーバーソケットにオプションを設定してください。

次に、あなたの問題はaccept()ブロックであり、必要なときに停止できないため、スレッドを強制終了していると思います。悪い解決策。ここでの正解は、非同期 I/O、つまりselect()Windowspoll()の対応するものです。Advanced Winsock Samplesをご覧ください。

マルチスレッドアプリでの簡単な解決策は、is_it_time_to_stop_accepting_connections各 の前にいくつかのフラグをチェックaccept()し、停止する時間になったらフラグを反転してリッスンポートに接続することです (はい、同じプログラムで)。これにより、のブロックが解除され、accept()適切な操作が可能になりますclosesocket()

しかし、真剣に、非同期 I/O を読んでください。

于 2011-08-07T04:16:03.810 に答える