Winsock Server с помощью WinAPI Thread сбрасывает первое соединение - PullRequest
0 голосов
/ 15 декабря 2018

Я написал сервер, используя WINAPI с методом CreateThread ().Первый запрос на подключение всегда умирает.Все следующие запросы / темы работают как положено.Я понятия не имею, почему, так что я надеюсь, что кто-то может сказать мне.Вот рабочий пример, иллюстрирующий проблему.

DWORD WINAPI process_thread(LPVOID lpParam) {

    SOCKET current_client = (SOCKET)lpParam;
    char buf[1024];
    int res;

    while(1) {

        res = recv(current_client, buf, strlen(buf), 0);            
        if(res>0) {
            buf[res] = '\0';
            send(current_client, buf, strlen(buf), 0);
        }

    }
}

int main() {

    SOCKET sock;
    DWORD thread;    
    WSADATA wsaData;    
    SOCKADDR_IN server;

    WSAStartup(0x102,&wsaData);

    server.sin_family=AF_INET;
    server.sin_addr.s_addr=INADDR_ANY;
    server.sin_port=htons(123);

    sock=socket(AF_INET,SOCK_STREAM,0);    
    bind(sock,(SOCKADDR*)&server,sizeof(server));    
    listen(sock,5);

    SOCKET client;    
    SOCKADDR_IN from;
    int fromlen = sizeof(from);

    while(1) {

        client = accept(sock,(struct SOCKADDR*)&from,&fromlen);       
        CreateThread(NULL, 0,process_thread,(LPVOID)client, 0, &thread);

    }

    closesocket(sock);
    WSACleanup();

    return 0;

}

1 Ответ

0 голосов
/ 15 декабря 2018

Вы неправильно используете strlen() внутри своего кода потока.

При вызове recv() вам необходимо указать полный размер буфера.strlen() - неправильный способ получить это значение.Вместо этого используйте sizeof().

Затем, когда выйдет recv(), его возвращаемое значение точно скажет, сколько байтов в буфере допустимо.Опять же, strlen() - неправильный способ получить это значение.

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

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

Кроме того, у вашего main() есть утечка дескрипторов потоков, и он вообще не выполняет никакой обработки ошибок.

Вместо этого попробуйте что-то вроде этого:

bool sendAll(SOCKET sock, void *buf, int buflen)
{
    char *ptr = (char*) buf;
    int sent;

    while (buflen > 0) {
        sent = send(sock, ptr, buflen, 0);
        if (sent == SOCKET_ERROR) {
            return false;
        }
        ptr += sent;
        buflen -= sent;
    }

    return true;
}

DWORD WINAPI process_thread(LPVOID lpParam) {

    SOCKET client = (SOCKET) lpParam;
    char buf[1024], *ptr;
    int recvd;

    do {
        recvd = recv(client, buf, sizeof(buf), 0);            
        if (recvd <= 0) {
            break;
        }
        if (!sendAll(client, buf, recvd)) {
            break;
        }
    }
    while (true);

    closesocket(client);
    return 0;
}

int main() {

    WSADATA wsaData;
    SOCKET server, client;
    SOCKADDR_IN serveraddr;
    SOCKADDR_IN clientaddr;
    int res, clientaddrlen;
    HANDLE hThread;
    DWORD threadID;

    res = WSAStartup(MAKEWORD(2, 1), &wsaData);
    if (res != 0) {
        return 1;
    }

    ZeroMemory(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = INADDR_ANY;
    serveraddr.sin_port = htons(123);

    server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (server == INVALID_SOCKET) {
        WSACleanup();
        return 1;
    }

    res = bind(server, (SOCKADDR*) &serveraddr, sizeof(serveraddr));
    if (res == SOCKET_ERROR) {
        closesocket(server);
        WSACleanup();
        return 1;
    }

    res = listen(server, 5);
    if (res == SOCKET_ERROR) {
        closesocket(server);
        WSACleanup();
        return 1;
    }

    do {
        clientaddrlen = sizeof(clientaddr);

        client = accept(server, (SOCKADDR*) &clientaddr, &clientaddrlen);
        if (client == INVALID_SOCKET) {
            closesocket(server);
            WSACleanup();
            return 1;
        }

        hThread = CreateThread(NULL, 0, process_thread, (LPVOID) client, 0, &threadID);
        if (hThread)
            CloseHandle(hThread);
        else
            closesocket(client);
    }
    while (true);

    closesocket(server);
    WSACleanup();

    return 0;
}
...