3

ソケット サーバーのように機能するソフトウェアを作成しました (インフラストラクチャ内の 3 つのノード間でパケットをディスパッチします)。簡単にするために、TCPソケットごとに1つずつ、3つのスレッドを作成しました(これが最適ではないことはわかっていますが、私の目的では、これが最も単純なオプションであり、最速でもありました)。すべてがうまく機能しています。サーバーの起動時に、3 つのソケットが通常の初期化 (getaddr、listen、bind など) を実行し、3 つの異なるポートを listen します。クライアントを起動すると、クライアントは適切に接続し、データを送受信します。

問題は、1 つのクライアントが切断されるたびに、他のソケットも強制的に切断されて再起動されることです。これはちょっとした問題です。疑わしいコードがここにあるに違いありません (これは、スレッドから起動されたルーチンです)。

void ManageSocket1( void )
{
    while( true )
    {
        Socket* socket = new Socket( 27016, "SocketName" );
        if( socket->CreateSocket() )
        {
            socket->StartCommunication();
        }
        socket->CloseSocket();
        delete socket;
    }
}

void ManageSocket2( void )
{
    // clone of ManageSocket1
}

CreateSocket() はソケットの作成を担当し、StartCommunication() はデータを受信/送信します。これらの 2 つの方法については、「一般的な」TCP ソケットを開くコードであるため、コードを投稿する必要はありません。ManageSocketX() は、main() 内のスレッドによって起動され、その性質上、main() に戻ることはありません。

それが CreateSocket() です。

int Socket::CreateSocket( void )
{
res = WSAStartup( MAKEWORD( 2,2 ), &wsaData );

if( res != 0 ) 
{
    logBook->PrintMsg( socketName, "WSAStartup failed" );
    return ERROR;
}
else
{
    logBook->PrintMsg( socketName, "WSAStartup done" );
}

res = getaddrinfo( NULL, socketPort, &hints, &result );

if ( res != 0 ) 
{
    logBook->PrintMsg( socketName, "GetAddrInfo failed" );
    WSACleanup();
    return ERROR;
}
else
{
    logBook->PrintMsg( socketName, "GetAddrInfo succesful");
}

ListenSocket = socket( result->ai_family, result->ai_socktype, result->ai_protocol );

if( ListenSocket == INVALID_SOCKET ) 
{
    logBook->PrintMsg( socketName, "GetAddrInfo failed with error: ", WSAGetLastError() );
    freeaddrinfo( result );
    WSACleanup();
    return ERROR;
}
else
{
    logBook->PrintMsg( socketName, "Socket created succesfully");
}

res = bind( ListenSocket, result->ai_addr, ( int )result->ai_addrlen );
if( res == SOCKET_ERROR ) 
{
    logBook->PrintMsg( socketName, "Bind failed with error: ", WSAGetLastError() );
    freeaddrinfo( result );
    closesocket( ListenSocket );
    WSACleanup();
    return ERROR;
}
else
{
    logBook->PrintMsg( socketName, "Socket successfully bound");
}

freeaddrinfo( result );

if( listen( ListenSocket, SOMAXCONN ) == SOCKET_ERROR ) 
{
    logBook->PrintMsg( socketName, "Bind failed with error: ", WSAGetLastError() );     
    closesocket( ListenSocket );
    WSACleanup();
    return ERROR;
}
else
{
    logBook->PrintMsg( socketName, "Listening on port", atoi( socketPort ) );
}

ClientSocket = accept( ListenSocket, NULL, NULL );
if( ClientSocket == INVALID_SOCKET ) 
{
    logBook->PrintMsg( socketName, "Accept failed:", WSAGetLastError() );
    closesocket( ListenSocket );
    WSACleanup();
    return 1;
}
else
{
    logBook->PrintMsg( socketName, "Client connection accepted" );
}

return SUCCESS;
}

それが StartCom() です

void Socket::StartCommunication( void )
{
char recvbuf[BUFLEN];
int  recvbuflen = BUFLEN;

do
{
    res = recv( ClientSocket, recvbuf, recvbuflen, 0 );
    if( res > 0 ) 
    {
        logBook->PrintMsg( socketName, "Bytes received:", res );            
    } 
    else if( res == 0 )
    {
        logBook->PrintMsg( socketName, "Connection closing..." );
    }
    else 
    {
        logBook->PrintMsg( socketName, "Receive failed:", WSAGetLastError() );
        closesocket( ClientSocket );
        WSACleanup();
        return;
    }       
} 
while( res > 0 );
}
4

1 に答える 1

3

WSACleanup問題は、ソケットのいずれかが終了したときに呼び出していることです。ドキュメントから:

マルチスレッド環境では、WSACleanup はすべてのスレッドの Windows ソケット操作を終了します。

さらに遠く:

WSACleanup が呼び出されたときに開いていたソケットはリセットされ、closesocket が呼び出されたかのように自動的に割り当て解除されます。

于 2012-12-15T14:21:09.043 に答える