tcp套接字请求(c/linux)中的线程进程经过一段时间后连接被拒绝
我正在尝试创建一个每秒处理请求数的进程,在每个请求上创建一个新线程。然后,每个线程打开到地址(http端口)的套接字连接,发送HEAD请求,获取响应并关闭套接字。tcp套接字请求(c/linux)中的线程进程经过一段时间后连接被拒绝,c,tcp,connection,send,C,Tcp,Connection,Send,我正在尝试创建一个每秒处理请求数的进程,在每个请求上创建一个新线程。然后,每个线程打开到地址(http端口)的套接字连接,发送HEAD请求,获取响应并关闭套接字。 当我每秒发出3个以上的请求时,我遇到了问题,在函数的send()部分出现错误一段时间后,我的连接一直被拒绝。如果每秒输入更多请求,则会更早地出现错误。如果我每秒只发出2个请求,我根本不会出错。我怀疑我正在耗尽一些资源,但我找不到 下面是代码的基本结构 //declarations socketfd = socket(servinfo
当我每秒发出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 您可能用完的资源位于您连接的服务器上。您正在连接的计算机正在拒绝连接,因为它是:
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操作上添加超时,则使用非阻塞套接字,该操作可能确实会阻塞
但是,首先要在没有超时的情况下进行尝试,以确保它在没有超时的情况下全速工作