我正在尝试创建每秒请求数量的进程,在每个请求上创建新线程。然后每个线程打开套接字连接到地址(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提前。
答案 0 :(得分:1)
您可能耗尽的资源位于您要连接的服务器上。您连接的计算机拒绝连接,因为它是:
由于您总是在第三个连接上收到错误,因此您连接的服务器可能会限制每个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时退出。如果你想在这个recv操作上添加一个超时,可以使用非阻塞套接字块。
但首先尝试没有超时,以确保它可以全速运行而不会阻塞作为您当前的版本。
我怀疑由于名称和IP地址分辨率,初始连接速度很慢,并且因为数据被缓存而在后续调用中变得更快。