Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Close only one socket

Tags:

c++

tcp

sockets

I made a piece of software which acts like a socket server (dispatches packets between three nodes in a infrastructure). To make it simple I created three threads, one for each TCP socket (I know this is not optimal but for my purposes it was the simplest option and also the fastest), and everything is working great. At server start, the three socket perform the usual initialization (getaddr, listen, bind, etc) and listen to three different ports; as I launch a client, the client properly connect and send/recv data.

The issue is that: whenever one client disconnects, even the other sockets are forcefully disconnected and rebooted, and this is kinda a problem. I bet the suspicious code lies here (this is the routine launched from the thread):

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() is the responsible of socket creation, while StartCommunication() recv/sends data; for these two methods there is no need to post code because it's a "common" tcp socket-opening code. The ManageSocketX() are launched by threads in main() and never return to main() because of their nature.

That's 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;
}

and that's 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 );
}
like image 691
Socket2104 Avatar asked Sep 14 '26 14:09

Socket2104


1 Answers

The issue is that you are calling WSACleanup when any of the sockets terminates. From the documentation:

In a multithreaded environment, WSACleanup terminates Windows Sockets operations for all threads.

Further:

Sockets that were open when WSACleanup was called are reset and automatically deallocated as if closesocket were called.

like image 112
ethrbunny Avatar answered Sep 16 '26 02:09

ethrbunny