Winsock Connect вызывает сбой, если несколько потоков работает, отлично работает в одном потоке? - PullRequest
0 голосов
/ 20 декабря 2018

У меня есть приложение, которое должно загрузить список переменных файлов (изменения в зависимости от пользователя, что изменилось и т. Д.).Список может быть очень коротким или очень длинным (1000 файлов).Я запускаю рабочие потоки X со списком для загрузки каждого потока.Если я запускаю 1 поток, все работает нормально.Если я запускаю> 1 поток, он «может» аварийно завершить работу в __acrt_lock (однако я не называю это).Проблема в соединении winsock.Если я закомментирую этот вызов, он работает (очевидно, не загружает файл, но он не падает).

ЭТО ИСПОЛЬЗУЕТСЯ ДЛЯ РАБОТЫ ПОД СЕТЕЙ СТАРЫХ СТАРЫХ v110.Я обновился до цепочки v141, и теперь проблема возникает.Конечно, я использую многопоточные библиотеки.

У меня есть "ярлык" кода с преждевременными операторами возврата в разных местах, и я определил, что проблема заключается в единственной строке, вызывающей функцию winsock "connect",Глобальные переменные не используются (только частное локальное хранилище для потока).

bool Socket::connect(const char * adrs, int port) {

    lastErrCode = 0;
    myIP = adrs;
    myPort = port;

    if (inet_addr(adrs) == INADDR_NONE) {
        getHostByName(adrs, myIP);
    }
    else {
        myIP = adrs;
    }

    if ((me = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
        lastErrCode = WSAGetLastError();
        return (false);
    }

    SOCKADDR_IN sock;
    sock.sin_family = PF_INET;
    sock.sin_port = htons(port);
    sock.sin_addr.s_addr = inet_addr(myIP.str());
    return(false); //:DEBUG:

    if (::connect(me, (SOCKADDR*)&sock, sizeof(SOCKADDR)) == SOCKET_ERROR) {
        lastErrCode = WSAGetLastError();
        closesocket(me);
        me = INVALID_SOCKET;
        return (false);
    }

    return (true);

}

1 Ответ

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

Спасибо всем за ответы.Я решил проблему!В моем основном коде не было глупого насоса сообщений Windows (я обычно запускаю эти типы серверов в Linux).Я добавил это к основному коду, и теперь он работает отлично.

#ifdef _WIN32
    MSG msg;
    while (!Stopped && GetMessage(&msg, (HWND)NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
#else
    while (!Stopped) {
        Sleep(1000);
    }
#endif

Извините, я не выложил достаточно кода для запуска примера, но в коде winsock произошел 100% сбой вкак отладочная, так и выпускная сборки.Всегда с падением в RtlHeapxxx () или __acrt_lock ().С помощью обработчика сообщений я могу многократно запускать его без проблем.

Что касается проблемы gethostbyname, я вызывал свой внутренний метод GetHostByName (изменение регистра), и он вызывает более новую функцию getaddrinfo ().

UINT32 Socket::getHostByName(const char * name, Data& ip) {
    UINT32 iadrs = getHostByName(name);
    ip.format("%d.%d.%d.%d", (iadrs >> 24) & 0xFF, (iadrs >> 16) & 0xFF, (iadrs >> 8) & 0xFF, iadrs & 0xFF);
    return (iadrs);
}

UINT32 Socket::getHostByName(const char * name) {

    if (lastAddress == name) {
        return(lastResolution);
    }

    struct addrinfo hints;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    struct addrinfo * result = nullptr;
    if (getaddrinfo(name, "80", &hints, &result) != 0) {
        if (result != nullptr) {
            freeaddrinfo(result);
        }
        return (0);
    }

    for (struct addrinfo * ptr = result; ptr != nullptr; ptr = ptr->ai_next) {
        if (ptr->ai_family == AF_INET) {
            struct sockaddr_in * ip = (struct sockaddr_in *) ptr->ai_addr;
            UINT32 iadrs = (ip->sin_addr.S_un.S_un_b.s_b1 << 24) | (ip->sin_addr.S_un.S_un_b.s_b2 << 16) | (ip->sin_addr.S_un.S_un_b.s_b3 << 8) | (ip->sin_addr.S_un.S_un_b.s_b4);
            freeaddrinfo(result);
            lastAddress = name;
            lastResolution = iadrs;
            return (iadrs);
        }
    }

    freeaddrinfo(result);
    return (0);

}
...