[英]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.