У меня возникли проблемы с использованием std :: async, чтобы задачи выполнялись параллельно, когда задача связана с сокетом.стандартный C++ TCP-сокет, сбой при соединении с EINTR при использовании std :: async
Моя программа - простой сервер сокетов TCP, написанный в стандартном C++ для Linux. Когда клиент подключается, открывается выделенный порт и запускается отдельный поток, поэтому каждый клиент обслуживается в своем потоке.
Клиентские объекты содержатся на карте.
У меня есть функция для трансляции сообщения всем клиентам. Я изначально написал его, как показано ниже:
// ConnectedClient is an object representing a single client
// ConnectedClient::SendMessageToClient opens a socket, connects, writes, reads response and then closes socket
// broadcastMessage is the std::string to go out to all clients
// iterate through the map of clients
map<string, ConnectedClient*>::iterator nextClient;
for (nextClient = mConnectedClients.begin(); nextClient != mConnectedClients.end(); ++nextClient)
{
printf("%s\n", nextClient->second->SendMessageToClient(broadcastMessage).c_str());
}
Я тестировал это, и он работает с 3 клиентами одновременно. Сообщение поступает ко всем трем клиентам (по одному за раз), а строка ответа печатается три раза в этом цикле. Тем не менее, он медленный, потому что сообщение отправляется только одному клиенту за раз.
Чтобы сделать его более эффективным, я надеялся использовать std :: async для вызова функции SendMessageToClient для каждого клиента асинхронно. Я переписал код, указанный выше, как это:
vector<future<string>> futures;
// iterate through the map of clients
map<string, ConnectedClient*>::iterator nextClient;
for (nextClient = mConnectedClients.begin(); nextClient != mConnectedClients.end(); ++nextClient)
{
printf("start send\n");
futures.push_back(async(launch::async, &ConnectedClient::SendMessageToClient, nextClient->second, broadcastMessage, wait));
printf("end send\n");
}
vector<future<string>>::iterator nextFuture;
for(nextFuture = futures.begin(); nextFuture != futures.end(); ++nextFuture)
{
printf("start wait\n");
nextFuture->wait();
printf("end wait\n");
printf("%s\n", nextFuture->get().c_str());
}
Код выше функции, как ожидается, когда есть только один клиент на карте. То, что вы быстро видите «начать отправку», за которым следует «конец отправки», быстро следует «начать ждать», а затем через 3 секунды (у меня есть три секунды сна на стороне ответа клиента, чтобы проверить это), вы видите трассировку из сокета прочитайте функцию, в которую приходит ответ, а затем вы увидите «конец ожидания»
Проблема в том, что при наличии на карте более одного клиента. В рамках функции SendMessageToClient, которая открывается и подключается к розетке, он не в коде, указанной ниже:
// connected client object has a pipe open back to the client for sending messages
int clientSocketFileDescriptor;
clientSocketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0);
// set the socket timeouts
// this part using setsockopt is omitted for brevity
// host name
struct hostent *server;
server = gethostbyname(mIpAddressOfClient.c_str());
if (server == 0)
{
close(clientSocketFileDescriptor);
return "";
}
//
struct sockaddr_in clientsListeningServerAddress;
memset(&clientsListeningServerAddress, 0, sizeof(struct sockaddr_in));
clientsListeningServerAddress.sin_family = AF_INET;
bcopy((char*)server->h_addr, (char*)&clientsListeningServerAddress.sin_addr.s_addr, server->h_length);
clientsListeningServerAddress.sin_port = htons(mPortNumberClientIsListeningOn);
// The connect function fails !!!
if (connect(clientSocketFileDescriptor, (struct sockaddr *)&clientsListeningServerAddress, sizeof(clientsListeningServerAddress)) < 0)
{
// print out error code
printf("Connected client thread: fail to connect %d \n", errno);
close(clientSocketFileDescriptor);
return response;
}
Выхода гласит: «Connected клиентского потока: не удается подключиться 4».
Я смотрел этот код ошибки вверх, это объясняется следующим образом:
#define EINTR 4 /* Interrupted system call */
Я искал вокруг в Интернете, все, что я нашел некоторые ссылки на системные вызовы прерывается сигналами.
Кто-нибудь знает, почему это работает, когда я вызываю функцию отправки сообщений по одному, но это не удается, когда функция отправки сообщения вызывается с использованием async? Кто-нибудь имеет другое предложение, как я должен отправить сообщение нескольким клиентам?