繁体   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