2013-08-22 33 views
0

我在使用std :: async在任务涉及套接字时并行执行任务时遇到问题。标准C++ TCP套接字,当使用std :: async时连接失败和EINTR

我的程序是用标准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

首先,我会尝试处理EINTR问题。 connect()已被中断(这是EINTR的含义),并且不会再次尝试,因为您正在使用和异步描述符。 我通常在这种情况下做的是重试:我在一段时间内封装函数(在这种情况下连接)。如果连接成功,我会跳出循环。如果失败,我检查errno的值。如果是EINTR,我再试一次。 请注意,还有其他errno值应该重试(EWOULDBLOCK是其中之一)