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

tcp套接字请求(c/linux)中的线程进程经过一段时间后连接被拒绝,c,tcp,connection,send,C,Tcp,Connection,Send,我正在尝试创建一个每秒处理请求数的进程,在每个请求上创建一个新线程。然后,每个线程打开到地址(http端口)的套接字连接,发送HEAD请求,获取响应并关闭套接字。 当我每秒发出3个以上的请求时,我遇到了问题,在函数的send()部分出现错误一段时间后,我的连接一直被拒绝。如果每秒输入更多请求,则会更早地出现错误。如果我每秒只发出2个请求,我根本不会出错。我怀疑我正在耗尽一些资源,但我找不到 下面是代码的基本结构 //declarations socketfd = socket(servinfo

我正在尝试创建一个每秒处理请求数的进程,在每个请求上创建一个新线程。然后,每个线程打开到地址(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; 
    }
}
//声明
socketfd=socket(servinfo->ai_系列,servinfo->ai_socktype,servinfo->ai_协议);
arg=fcntl(socketfd,F_GETFL,NULL))<0);
arg |=O|u非块;
fcntl(插座FD、F_设置FL、arg)
如果((conn=connect(socketfd,servinfo->ai_addr,servinfo->ai_addrlen))<0)
{
如果(errno==EINPROGRESS)
{
做
{
tv.tv_sec=连接超时;
tv.tv_usec=0;
FD_ZERO(&myset);
FD_集(socketfd和myset);
if((res=select(socketfd+1,NULL,&myset,NULL,&tv)>0))
{
如果((arg=fcntl(socketfd,F_GETFL,NULL))<0{
perror(“fcntl获得2”);
} 
arg&=(~O_非块);
如果(fcntl(socketfd,F_SETFL,arg)<0){
perror(“fcntl第2套”);
}
char-szBuf[4096];
std::string htmlreq=“HEAD/HTTP/1.1\r\nHost:”;
htmlreq+=信息->主机名;
htmlreq+=“\r\n\r\n”;
如果((conn=send(socketfd,htmlreq.c_str(),htmlreq.size(),0))=-1&&errno!=EINTR)
{
佩罗(“发送”);
关闭(socketfd);
返回;
}
如果((conn=recv(socketfd,szBuf,sizeof(szBuf)+1,0))<0&&errno!=EINTR)
{
perror(“recv”);
关闭(socketfd);
返回;
}
关闭(socketfd);
//处理数据
打破
}
其他的
{
//超时
打破
}
}而(1),;
}
其他的
{
perror(“连接”);
关闭(socketfd);
返回;
}
}

我从一开始就删除了一些错误检查,经过一段时间后,我得到的输出是“发送:连接被拒绝”。我很想知道是哪一部分导致了问题,平台是UbuntuLinux。如果需要,我也很乐意发布代码的其他部分。提前通知Tnx

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

  • 配置以限制每秒的连接数(基于某些条件)
  • 或者由于某种原因,您连接到的服务器负载过大,无法进行更多连接
  • 由于在第三次连接时总是出现错误,可能是您连接的服务器限制了每个IP的连接数

    Edit1

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

    这是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);
    
    FD_ZERO(&rset);
    FD_集(sockfd和rset);
    wset=rset;
    tval.tv_sec=nsec;
    tval.tv_usec=0;
    如果((n=Select(sockfd+1,&rset,&wset,NULL,
    nsec?&tval:NULL))==0){
    关闭(sockfd);/*超时*/
    errno=ETIMEDOUT;
    返回(-1);
    }
    if(FD_-ISSET(sockfd和rset)| | FD_-ISSET(sockfd和wset)){
    len=sizeof(错误);
    if(getsockopt(sockfd,SOL_SOCKET,SO_ERROR,&ERROR,&len)<0)
    返回(-1);/*Solaris挂起错误*/
    }否则
    err_quit(“选择错误:sockfd未设置”);
    完成:
    Fcntl(sockfd、F_SETFL、flags);/*还原文件状态标志*/
    如果(错误){
    关闭(sockfd);/*以防万一*/
    errno=错误;
    返回(-1);
    }
    返回(0);
    
    您的代码中有很多问题

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

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

    你显然想先发邮件的标题。除非您预期远程服务器或网络速度非常慢,并且希望在其上暂停一段时间,否则没有真正的必要使其成为非阻塞的。在这种情况下,select with non blocking套接字将使sens

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

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

    但是,首先要在没有超时的情况下进行尝试,以确保它在没有超时的情况下全速工作