在tcp套接字请求(c / linux)中的线程进程一段时间后连接被拒绝

时间:2009-05-11 10:06:44

标签: c tcp connection send

我正在尝试创建每秒请求数量的进程,在每个请求上创建新线程。然后每个线程打开套接字连接到地址(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; 
    }
}

我从开始删除了一些错误检查,一段时间后输出的内容是“Send:Connection Refused”。我很欣赏一些可能导致问题的部分指针,平台是ubuntu linux。如果需要,我也很乐意发布其他代码部分。 Tnx提前。

2 个答案:

答案 0 :(得分:1)

您可能耗尽的资源位于您要连接的服务器上。您连接的计算机拒绝连接,因为它是:

  1. 配置以限制每秒的连接数(基于某些条件)
  2. 或者您连接的服务器由于某种原因负载过大而无法再接入。
  3. 由于您总是在第三个连接上收到错误,因此您连接的服务器可能会限制每个IP的连接数。

    <强> EDIT1

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

    这是来自Stevens 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);
    

答案 1 :(得分:0)

您的代码中存在很多问题。

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

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

您显然希望先发送HEAD消息。除非您希望远程服务器或网络速度非常慢并且想要超时,否则没有必要使这个非阻塞。在这种情况下,选择非阻塞套接字会产生感觉。

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

所以recv应该被包装到一个循环中,你将接收到的数据附加到某个缓冲区或文件,当recv返回0时退出。如果你想在这个rec​​v操作上添加一个超时,可以使用非阻塞套接字块。

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

我怀疑由于名称和IP地址分辨率,初始连接速度很慢,并且因为数据被缓存而在后续调用中变得更快。