簡體   English   中英

標准C ++ TCP套接字,使用std :: async時,連接失敗並使用EINTR

[英]standard C++ TCP socket, connect fails with EINTR when using std::async

當任務涉及套接字時,我無法使用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秒鍾后(我在客戶端響應端有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 */

我在互聯網上四處搜尋,發現所有被信號中斷的系統調用的引用。

有誰知道為什么一次調用一次我的發送消息功能時這種方法有效,但是當使用異步調用發送消息功能時卻失敗了嗎? 有人對我應該如何向多個客戶端發送消息有不同的建議嗎?

首先,我將嘗試處理EINTR問題。 connect()已被中斷(這是EINTR的含義),並且不會再試一次,因為您正在使用andynch描述符。 在這種情況下,我通常要做的是重試:我會在一段時間內包裝該函數(在這種情況下為連接)。 如果連接成功,我將退出周期。 如果失敗,則檢查errno的值。 如果是EINTR,請重試。 請注意,還有其他errno值值得重試(EWOULDBLOCK是其中之一)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM