Многопоточная проблема клиент-сервер - PullRequest
0 голосов
/ 13 сентября 2011

Я сталкиваюсь со специфической проблемой с моим клиентским серверным приложением. Я написал консольный многопоточный клиентский сервер. Несколько клиентов пытаются отправлять и получать данные тысячи раз. Когда я запускаю более одного клиента, мой старый клиент перестает отправлять получаемые данные, и новый клиент начинает работу. Я не могу понять, почему мой первый клиент блокируется при запуске другого клиента.

Здесь я добавил код. Это операции TCP. Я только что упомянул ключевые функции.

bool LicTCPServer::Initialize()
{
    m_socketAccept = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP );
    if (m_socketAccept == INVALID_SOCKET)
        return false;

    int *p_int;
    p_int = (int*)malloc(sizeof(int));
    *p_int = 1;
    if( (setsockopt(m_socketAccept, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 )||
        (setsockopt(m_socketAccept, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){
        printf("Error setting options %d\n", WSAGetLastError());
        free(p_int);
    }
    free(p_int);

    /*int iMode = 1;
    ioctlsocket(m_socketAccept, FIONBIO, (u_long FAR*) &iMode);*/

    SOCKADDR_IN oSockAddr;
    ::ZeroMemory(&oSockAddr, sizeof(SOCKADDR_IN));
    oSockAddr.sin_family = AF_INET;
    oSockAddr.sin_port = htons(m_wPortNoServer);
    oSockAddr.sin_addr.s_addr = m_dwInetAddrServer;

    int ret = bind(m_socketAccept, (const sockaddr*) &oSockAddr, sizeof(SOCKADDR_IN));

    int error;
    if (ret == SOCKET_ERROR)
    {
        closesocket(m_socketAccept);
        error = WSAGetLastError();
        return false;
    }

    error = listen(m_socketAccept,  SOMAXCONN);
    DWORD temp = GetLastError();
    if (error == SOCKET_ERROR)
        return false;

    return true;
}

bool LicTCPServer::CheckConnection(struct sockaddr_in *clientAddress, SOCKET *sockValue)
{
    //struct sockaddr_in clientAddress1;
    int clientAddressLen = sizeof(struct sockaddr_in);
    //struct sockaddr_in clientAddress;    // Address of the client that sent data
    SOCKET socket = accept(m_socketAccept, (struct sockaddr *)clientAddress, &clientAddressLen);
    printf("Port - %d \n",clientAddress->sin_port);
    //m_socketConnect = socket;
    *sockValue = socket;
    return true;
}

int LicTCPServer::ReceiveData(SOCKET socketNo, char* pszBuf, int & bufLen)
{
    /*struct timeval tvTimeout;
    tvTimeout.tv_sec = 0;
    tvTimeout.tv_usec = (long) (10 * 1000);

    fd_set fdSet;
    FD_ZERO(&fdSet);
    FD_SET(socketNo, &fdSet);
    long lStatus = select(socketNo + 1, &fdSet, NULL, NULL, &tvTimeout);
    if (lStatus <= 0)
    {
        FD_ZERO(&fdSet);
    }
    if (!FD_ISSET(socketNo, &fdSet))
    {
        return 0;
    }*/

    /*if (!CanReadOnBlockingSocket(socketNo))
    {
        return TELEGRAM_RECEIVE_ERROR;
    }*/

    bufLen = recv(socketNo, pszBuf, 10, 0);

    if(bufLen == -1)
        return WSAGetLastError();
    else if(bufLen == 0)
    {
        closesocket(socketNo);
        return -1;
    }
    else
        return 0;
}

bool LicTCPServer::SendData(SOCKET socketNo, BYTE *puchBuf, int iBufLen)
{
    int ret = send(socketNo, (char*)puchBuf, iBufLen,0);

    //printf("Sent from server: %d %d\n\n",test2.a,test2.b);
    return true;
}

Вот моя основная функция ():

void ClientServerCommunication(void *dummy);
struct informationToClient
{
    LicTCPServer *serverFunctions;
    SOCKET clientSocketNo;
}infoToClient;

int _tmain(int argc, _TCHAR* argv[])
{

    DWORD dwInetAddrServer = inet_addr("127.0.0.1");

    if(dwInetAddrServer == INADDR_NONE)
        return 0;

    WORD dwPortNumber = 2001;

    LicTCPServer server(dwInetAddrServer, dwPortNumber);

    server.Initialize();
    struct sockaddr_in clientAddress; 
    SOCKET sockValue;

    infoToClient.serverFunctions = &server;
    while(1)
    {
        bool retValue = server.CheckConnection(&clientAddress, &sockValue);

        if( sockValue == INVALID_SOCKET )
        {
            Sleep(10000);
            continue;//or exit from thread
        }
        infoToClient.clientSocketNo = sockValue;
        //retrieve client information from Make Connection and put it into LicenseClientData class
        //Create thread for each client which will receive or send data
        _beginthread(ClientServerCommunication, 0, (void *)&infoToClient);
        //delete 

    }
    return 0;
}



void ClientServerCommunication(void *dummy)
{
    int iRetValue;
    informationToClient *socketInfo =  (informationToClient *)dummy;
    char szBuf[10];
    int iBufLen = 0;
    while(1)
    {
        iRetValue = socketInfo->serverFunctions->ReceiveData(socketInfo->clientSocketNo, szBuf, iBufLen);
        printf("Data received on socket %d %s\n", socketInfo->clientSocketNo, szBuf);
        if(iRetValue == WSAECONNRESET)
        {
            _endthread();
        }
        socketInfo->serverFunctions->SendData(socketInfo->clientSocketNo, (BYTE*)szBuf, iBufLen);
        printf("Data sent on socket %d %s\n", socketInfo->clientSocketNo, szBuf);
    }
}

Весь код, упомянутый выше, является тестовым кодом. Как только он работает нормально, я должен использовать класс LicTCPServer в своем приложении.

1 Ответ

0 голосов
/ 13 сентября 2011

Есть много возможных ошибок.

Ваше описание согласуется с тем, что вы сохраняете «соединение» как глобальную переменную, а не присваиваете каждому потоку на сервере свой собственный экземпляр соединения.


Обновление:

быстрый взгляд на код, infoToClient глобален.

...