当任务涉及套接字时,我无法使用std :: async让任务并行执行。
我的程序是一个用标准C ++ for Linux编写的简单TCP套接字服务器。当客户端连接时,会打开一个专用端口并启动单独的线程,因此每个客户端都在自己的线程中进行服务。
客户端对象包含在地图中。
我有一个向所有客户端广播消息的功能。我最初写的如下:
// 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;
}
输出显示:“已连接的客户端线程:无法连接4”。
我看了这个错误代码,因此解释了:
#define EINTR 4 /* Interrupted system call */
我在互联网上搜索过,我发现所有这些都是系统调用被信号中断的一些参考。
当我一次调用一个发送消息函数时,有没有人知道为什么会这样,但是当使用异步调用发送消息函数时它会失败?有没有人有不同的建议我应该如何向多个客户发送消息?
答案 0 :(得分:0)
首先,我会尝试处理EINTR问题。 connect()已被中断(这是EINTR的含义)并且不再尝试,因为您正在使用和异步描述符。 在这种情况下我通常做的是重试:我在一个while循环中包装函数(在这种情况下连接)。如果连接成功,我就会突破循环。如果失败,我检查errno的值。如果是EINTR,我再试一次。 请注意,还有其他值的errno值得重试(EWOULDBLOCK就是其中之一)