Невозможность асинхронного вызова recvfrom()

119
25 августа 2019, 13:50

Вызов recvfrom() из вызванной асинхронно функции блокирует не только нить, в которой функция, но и вызывавший поток (возврат в него не происходит). Почему и как это обойти?

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

pps vs2017 solution

Answer 1

recvfrom - блокирующая функция (ОС Виндовс)
https://docs.microsoft.com/en-us/windows/desktop/api/winsock/nf-winsock-recvfrom

...

if no incoming data is available at the socket, the recvfrom function blocks and waits for data to arrive according to the blocking rules defined for WSARecv with the MSG_PARTIAL flag not set unless the socket is nonblocking. In this case, a value of SOCKET_ERROR is returned with the error code set to WSAEWOULDBLOCK. The select, WSAAsyncSelect, or WSAEventSelect can be used to determine when more data arrives.

...

Попробуйте использовать асинхронные операции WSA2: https://docs.microsoft.com/en-us/windows/desktop/api/winsock2/nf-winsock2-wsarecv

std::async не гарантирует выполнения в отдельном потоке и содержит кучу ограничений на асинхронный запуск, и, вполне естественно, что у вас зависает весь поток.

Answer 2

Спасибо всем за помощь, вот решение:

bool UdpClient::stopListen = false;
void UdpClient::listen(SOCKET RecvSocket, sockaddr_in addr, onReceive o, UdpClient::onError _onError)
{
    int size = sizeof(addr);
    char rBuff[1024];
    int buffSize = sizeof(rBuff);
    while (stopListen) {
        int err = recvfrom(RecvSocket, rBuff, sizeof(rBuff), 0, (sockaddr*)&addr, &buffSize);
        if (err > 0) {
            rBuff[err] = 0;
            if (o)
                o(rBuff);
        }
        else {
            if (_onError) {
                std::ostringstream out;
                out << "recv failed: " << WSAGetLastError();
                _onError(out.str());
            }
            closesocket(RecvSocket);
            WSACleanup();
            return;
        }
    }
}
std::shared_future<void> UdpClient::receive(onReceive r, int port, const std::string& ip)
{
    std::ostringstream out;
    std::future<void> k;
    std::shared_future<void> m;
    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR) {
        if (_onError) {
            out << "WSAStartup failed with error: " << iResult;
            _onError(out.str());
        }
        return m;
    }
    sockaddr_in ServerAddr;
    ServerAddr.sin_family = AF_INET;
    ServerAddr.sin_port = htons(port);
    inet_pton(AF_INET, ip.c_str(), &ServerAddr.sin_addr);
    SOCKET RecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (RecvSocket == INVALID_SOCKET) {
        if (_onError) {
            out << "socket failed with error: " << WSAGetLastError();
            _onError(out.str());
        }
        WSACleanup();
        return m;
    }
    int err = bind(RecvSocket, (sockaddr*)&ServerAddr, sizeof(ServerAddr));
    if (err == SOCKET_ERROR) {
        if (_onError) {
            out << "bind failed with error: " << WSAGetLastError();         
            _onError(out.str());
        }
        closesocket(RecvSocket);
        WSACleanup();
        return m;
    }
    auto n = std::async(std::launch::async, listen, RecvSocket, ServerAddr, r, _onError).share();
    //std::shared_future<std::future<void>> f(n);
    return n;
}
READ ALSO
Данные в загруженном файле не меняются

Данные в загруженном файле не меняются

Я недавно начал заниматься C++, и пишу простую программку которая получает данные из файла который находится в интернетеСама функция:

100
Определить возвращаемый тип перегруженной функции в шаблоне

Определить возвращаемый тип перегруженной функции в шаблоне

У меня возникает проблема с определением типа возвращаемого значения перегруженной функции внутри шаблонаВозвращаемый тип зависит от параметра,...

96
Как использовать CefCookieManager вместе с java.net.URL

Как использовать CefCookieManager вместе с java.net.URL

Куки заранее получил через авторизацию браузера CefBrowserДелаю так:

124