2013-08-22 35 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是其中之一)