Вызов recvfrom() из вызванной асинхронно функции блокирует не только нить, в которой функция, но и вызывавший поток (возврат в него не происходит). Почему и как это обойти?
ps Это, если верно считаю, уже третья тема по советам переформулировать и задать новый вопрос в предыдущих, где никто ничем не смог помочь, в чём любой может убедиться, если почитает предыдущие темы внимательно, а именно мои комментарии к ответам.
pps vs2017 solution
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 не гарантирует выполнения в отдельном потоке и содержит кучу ограничений на асинхронный запуск, и, вполне естественно, что у вас зависает весь поток.
Спасибо всем за помощь, вот решение:
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;
}
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости