TCP Winsock: принимать несколько соединений/клиентов

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

while(true)
{
    if(Sub = accept(Socket, (sockaddr*)&IncomingAddress, &AddressLen))
    {
        for(int i = 0; i < MaxUsers; i++)
        {
            if(!ClientAddress[i].sin_family)
            {
                ClientAddress[i] = IncomingAddress;
                char Version[128], Dir[256], Path[256], URL[128], Message[256];
                GetCurrentDirectory(256, Dir);
                sprintf(Path, "%s\\Version.ini", Dir);
                GetPrivateProfileString("Default", "Version", "1.0.0.0", Version, 128, Path);
                GetPrivateProfileString("Default", "URL", "", URL, 128, Path);
                GetPrivateProfileString("Default", "Message", "", Message, 256, Path);
                send(Sub, Version, 128, 0);
                send(Sub, Message, 256, 0);
                break;
            }
        }
        continue;

    }
}

person Ido Hadar    schedule 03.03.2013    source источник


Ответы (2)


Конечно, новые клиенты не могут быть приняты, потому что сервер обрабатывает только что принятых клиентов, т.е. сервер занят.

Решение простое: создайте новый поток для каждого принятого клиента и обработайте там клиентский сеанс. Просто используйте _beginthreadex() (#include <process.h>):

unsigned __stdcall ClientSession(void *data)
{
    SOCKET client_socket = (SOCKET)data;
    // Process the client.
}

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

    SOCKET client_socket;
    while ((client_socket = accept(server_socket, NULL, NULL))) {
        // Create a new thread for the accepted client (also pass the accepted client socket).
        unsigned threadID;
        HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, &ClientSession, (void*)client_socket, 0, &threadID);
    }
}

Кстати, send()/recv() функции не гарантируют, что все данные будут отправлены/получены за один вызов. Пожалуйста, смотрите документацию для возвращаемого значения этих функций.

person Sergey Vyacheslavovich Brunov    schedule 03.03.2013

После принятия сокета создайте отдельный поток для клиентских запросов. Затем продолжайте ждать нового принятия.

Например:

    ...
    while (1)
    {
        AcceptSocket = SOCKET_ERROR;

        while (AcceptSocket == SOCKET_ERROR )
        {
            AcceptSocket = accept( m_socket, NULL, NULL );
        }

        printf( "Client Connected.\n");

        DWORD dwThreadId;
        CreateThread (NULL, 0, ProcessClient, (LPVOID) AcceptSocket, 0, &dwThreadId);
    }
    ...

Где функция ProcessClient может быть такой:

DWORD WINAPI ProcessClient (LPVOID lpParameter)
{
    SOCKET AcceptSocket = (SOCKET) lpParameter;

    // Send and receive data.
    int bytesSent;
    int bytesRecv = SOCKET_ERROR;
    char sendbuf[2000]="";
    char recvbuf[2000]="";

    char timebuf[128];

    sprintf(sendbuf, "Hello, it's a test server at %s:%d (commands: 1, 2, exit)\n", ipaddr, port);
    bytesSent = send( AcceptSocket, sendbuf, strlen(sendbuf), 0);

    if (bytesSent == SOCKET_ERROR)
    {
        printf( "Error at send hello: %ld\n", WSAGetLastError());
        goto fin;
    }

    while (1)
    {
        _strtime( timebuf );
        ZeroMemory (recvbuf, sizeof(recvbuf));

        bytesRecv = recv( AcceptSocket, recvbuf, 32, 0);
        printf( "%s Client said: %s\n", timebuf, recvbuf);

        if (strcmp(recvbuf, "1") == 0)
        {
            sprintf(sendbuf, "You typed ONE\n");
            //printf("Sent '%s'\n", sendbuf);
            bytesSent = send( AcceptSocket, sendbuf, strlen(sendbuf), 0);

            if (bytesSent == SOCKET_ERROR)
            {
                printf( "Error at send: %ld\n", WSAGetLastError());
                goto fin;
            }
        }
        else if (strcmp(recvbuf, "2") == 0)
        {
            sprintf(sendbuf, "You typed TWO\n");
            //printf("Sent '%s'\n", sendbuf);
            bytesSent = send( AcceptSocket, sendbuf, strlen(sendbuf), 0);

            if (bytesSent == SOCKET_ERROR)
            {
                printf( "Error at send: %ld\n", WSAGetLastError());
                goto fin;
            }
        }
        else if (strcmp(recvbuf, "exit") == 0)
        {
            printf( "Client has logged out\n", WSAGetLastError());
            goto fin;
        }
        else
        {
            sprintf(sendbuf, "unknown command\n");
            //printf("Sent '%s'\n", sendbuf);
            bytesSent = send( AcceptSocket, sendbuf, strlen(sendbuf), 0);

            if (bytesSent == SOCKET_ERROR)
            {
                printf( "Error at send: %ld\n", WSAGetLastError());
                goto fin;
            }
        }
    }

fin:
    printf("Client processed\n");

    closesocket(AcceptSocket);
    return 0;
}
person Pavel Malinnikov    schedule 03.03.2013