0

我正在尝试创建每秒处理请求数的过程,在每个请求上创建新线程。然后每个线程打开套接字连接到地址(http 端口)发送 HEAD 请求,获得响应并关闭套接字。
当我每秒发出超过 3 个请求时,我遇到了问题,一段时间后,我在函数的 send() 部分出现错误,我不断收到连接被拒绝。如果我每秒输入更多请求,我会更早地收到错误。如果我每秒只发出 2 个请求,我根本不会收到错误消息。我怀疑我的一些资源用完了,但我找不到哪个。

这是代码的基本结构

//declarations

socketfd = socket(servinfo->ai_family,servinfo->ai_socktype,servinfo->ai_protocol);

arg = fcntl(socketfd, F_GETFL, NULL)) < 0);
arg |= O_NONBLOCK;
fcntl(socketfd, F_SETFL, arg)

if((conn = connect(socketfd, servinfo->ai_addr, servinfo->ai_addrlen)) < 0)
{
    if(errno == EINPROGRESS)
    {
        do
        {
            tv.tv_sec = CONNECT_TIMEOUT;
            tv.tv_usec = 0;
            FD_ZERO(&myset);
            FD_SET(socketfd, &myset);
            if((res = select(socketfd+1, NULL, &myset, NULL, &tv) > 0)) 
            {
                if( (arg = fcntl(socketfd, F_GETFL, NULL)) < 0) { 
                    perror("fcntl get 2");
                } 
                arg &= (~O_NONBLOCK); 
                if( fcntl(socketfd, F_SETFL, arg) < 0) {
                    perror("fcntl set 2");
                }
                char szBuf[4096];

                std::string htmlreq = "HEAD / HTTP/1.1\r\nHost:";
                htmlreq += info->hostName;
                htmlreq += "\r\n\r\n";

                if((conn = send(socketfd,htmlreq.c_str(),htmlreq.size(),0)) == -1 && errno != EINTR)
                {
                    perror("send");
                    close(socketfd);
                    return;
                }

                if((conn = recv(socketfd,szBuf,sizeof(szBuf)+1,0)) < 0 && errno != EINTR)
                {
                    perror("recv");
                    close(socketfd);
                    return ;
                }

                close(socketfd);

                // do stuff with data
                break;
            }
            else
            {
                //timeout
                break;
            }
        }while(1);
    }
    else
    {
        perror("connect");
        close(socketfd);
        return; 
    }
}

我从一开始就删除了一些错误检查,一段时间后我得到的输出是“发送:连接被拒绝”。我很感激一些关于可能导致问题的部分的指针,平台是 ubuntu linux。如果需要,我也很乐意发布代码的其他部分。提前Tnx。

4

2 回答 2

1

您可能用完的资源在您要连接的服务器上。您要连接的计算机拒绝连接,因为它是:

  1. 配置以限制每秒的连接数(基于某些标准)
  2. 或者您要连接的服务器由于某种原因负载过大,无法再进行连接。

由于您总是在第三个连接上遇到错误,因此您连接的服务器可能会限制每个 IP 的连接数。

编辑1

您正在尝试进行非阻塞连接?现在我仔细看了一下,听起来您的问题出在 select 上,因为在 select 中返回的是套接字在实际连接之前是可读的,然后您正在调用 send。在非阻塞连接上要注意的一件事是套接字在出错时变得可读和可写。这意味着您需要在 select 返回后检查两者,否则您可能会错过实际错误,而是看到发送错误。

这是来自史蒂文斯 UNP:

FD_ZERO(&rset);
FD_SET(sockfd, &rset);
wset = rset;
tval.tv_sec = nsec;
tval.tv_usec = 0;

if ( (n = Select(sockfd+1, &rset, &wset, NULL,
                 nsec ? &tval : NULL)) == 0) {
    close(sockfd);      /* timeout */
    errno = ETIMEDOUT;
    return(-1);
}

if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
    len = sizeof(error);
    if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
        return(-1);         /* Solaris pending error */
} else
    err_quit("select error: sockfd not set");

done:
Fcntl(sockfd, F_SETFL, flags);  /* restore file status flags */

if (error) {
    close(sockfd);      /* just in case */
    errno = error;
    return(-1);
}
return(0);
于 2009-05-11T10:37:20.550 回答
0

您的代码中有很多问题。

首先,您将套接字设置为非阻塞。我不明白你为什么这样做。connect 函数有一个内部超时,因此不会阻塞。

您的代码的另一个问题是,如果连接立即成功,第一个 if 语句将跳过指令块!这可能会发生。

您显然想先发送 HEAD 消息。除非您期望远程服务器或网络非常慢并且想要超时,否则没有真正需要使这个成为非阻塞的。在这种情况下,带有非阻塞套接字的选择会很有意义。

发送 HEAD 消息后,您期望使用 recv 函数收集一些数据作为响应。请注意,此函数调用可能会在接收到发送的全部数据之前返回。您需要一种独立的方式来确定是否已收到所有发送的数据。服务器会关闭连接吗?这将由返回 0 的 recv 函数检测到。

因此,recv 应该被包装到一个循环中,您可以将接收到的数据附加到某个缓冲区或文件中,并在 recv 返回 0 时退出。如果您想在此可能确实阻塞的 recv 操作上添加超时,请使用非阻塞套接字。

但首先尝试不超时,以确保它可以全速运行而不会像您当前的版本那样阻塞。

我怀疑由于名称和 IP 地址解析,初始连接速度很慢,并且由于缓存了数据,因此在后续调用中变得更快。

于 2009-05-11T14:57:18.110 回答