tcpsocket — стандартный C ++ TCP-сокет, сбой соединения с EINTR при использовании std :: async

У меня возникают проблемы с использованием 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());
}

Приведенный выше код работает, как и ожидалось, когда на карте только один клиент. То, что вы видите «start send», за которым быстро следует «end send», за которым следует «start wait», а затем через 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;
}

Вывод гласит: «Подключенный поток клиента: не удается подключиться 4».

Я посмотрел этот код ошибки, это объясняется так:

#define EINTR            4      /* Interrupted system call */

Я искал в Интернете, все, что я нашел, было несколько ссылок на системные вызовы, прерываемые сигналами.

Кто-нибудь знает, почему это работает, когда я вызываю функцию отправки сообщения по одному, но происходит сбой, когда функция отправки сообщения вызывается с использованием async? У кого-нибудь есть другое предложение, как мне отправить сообщение нескольким клиентам?

0

Решение

Во-первых, я бы попытался разобраться с проблемой EINTR. connect () был прерван (в этом смысл EINTR) и больше не пытается, потому что вы используете дескриптор asynch.
Что я обычно делаю в таких обстоятельствах, так это повторяю попытку: я оборачиваю функцию (подключаюсь в этом случае) через некоторое время. Если соединение успешно, я вырываюсь из цикла. Если это не удается, я проверяю значение errno. Если это EINTR, я пытаюсь снова.
Имейте в виду, что есть другие значения errno, которые заслуживают повторной попытки (EWOULDBLOCK — одно из них)

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]