在 tcp 套接字请求中的线程进程上一段时间后连接被拒绝 (c/linux)
我正在尝试创建每秒处理多个请求的进程,每个请求都会创建新线程。 然后每个线程打开到地址(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。
I'm trying to make process that takes number of requests each second, on each request new thread is created. Each thread then opens socket connection to address (http port) sends HEAD requests, gets response and closes socket.
Problem I'm having comes when i put more then 3 requests per second, after some time i get error in send() part of function, i keep getting Connection Refused. If I input more requests per second i get errors earlier. If i put only 2 requests per second i don't get errors at all. I suspect that I'm running out of some resource but i can't find which.
Here is basic structure of code
//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;
}
}
I removed some error checking from start, what i get as output is "Send: Connection Refused" after some time. I'd appreciate some pointers to what part could be causing problems, platform is ubuntu linux. I'd also be glad to post other parts of code if needed. Tnx in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可能耗尽的资源位于您正在连接的服务器上。 连接被您要连接的计算机拒绝,因为它是:
由于您总是在第三个连接上收到错误,因此可能是您要连接的服务器限制了每个 IP 的连接数。
编辑1
您正在尝试进行非阻塞连接吗? 现在我仔细看看它,听起来你的问题出在 select 上,因为在 select 中返回套接字在实际连接之前是可读的,然后你调用 send。 在非阻塞连接上需要注意的事情之一是套接字在发生错误时变得可读和可写。 这意味着您需要在 select 返回后检查两者,否则您可能会丢失任何实际错误并看到发送错误。
这是史蒂文斯 UNP 的:
The resource you're probably running out of is on the server you're connecting to. The connection is being refused by the computer you're connecting to because it's either:
Since you always get the error on the third connection it could be that the server you're connecting to limits the number of connections on a per IP basis.
Edit1
You're trying to do a non-blocking connect? Now that I look at it closer it sounds like your problem is with the select, as in select is returning that the socket is readable before it's actually connected and then you're calling send. One of the things to watch out for on non-blocking connects is that the socket becomes both readable and writeable on error. Which means you need to check for both after select returns otherwise you may be missing whatever the actual error is and seeing the send error instead.
This is from Stevens UNP:
您的代码中有很多问题。
首先,将套接字设置为非阻塞。 我不明白你为什么这样做。 连接函数有一个内部超时,因此不会阻塞。
代码的另一个问题是,如果连接立即成功,第一个 if 语句将跳过指令块! 这可能会发生。
您显然想首先发送 HEAD 消息。 没有真正需要使其成为非阻塞,除非您预计远程服务器或网络非常慢并且希望超时。 在这种情况下,使用非阻塞套接字进行选择是有意义的。
发送 HEAD 消息后,您期望使用 recv 函数收集一些响应数据。 请注意,此函数调用可能会在接收到发送的全部数据之前返回。 您需要一种独立的方式来确定所有发送的数据都已收到。 服务器会关闭连接吗? 这将被返回 0 的 recv 函数检测到。
因此,recv 应该被包装到一个循环中,在该循环中将接收到的数据附加到某个缓冲区或文件,并在 recv 返回 0 时退出。如果要添加超时,请使用非阻塞套接字在这个可能确实会阻塞的recv操作上。
但首先尝试不超时,以确保它全速工作而不会像当前版本那样阻塞。
我怀疑初始连接速度很慢,因为名称和 IP 地址解析,并且在后续调用中变得更快,因为数据被缓存。
There are quite a few problems in your code.
First you set the socket to non blocking. I don't understand why you do this. The connect function has an internal timeout and so won't block.
Another problem of your code is that the first if statement will skip the instruction block if the connection immediately succeeds ! Which may happen.
You apparently want to first send the HEAD message. There is no real need to make this one non blocking unless you expect the remote server or the network to be very slow and want a time out on it. In this case the select with non blocking socket would make sens.
Once you send the HEAD message, you expect some data in response that you collect with the recv function. Be aware that this function call may return before the whole data sent is received. You need an independent way to determine that all the data sent has been received. Would the server close the connection ? This would detected by the recv function returning 0.
So the recv should be wrapped into a loop where you append to received data to some buffer or a file and quit when recv returns 0. Use a non blocking socket if you want to add a timeout on this recv operation which may indeed block.
But first try without timeouts to be sure it works at full speed without blocking as your current version.
I suspect the initial connect is slow because of name and IP adresse resolution, and gets faster in subsequent calls because data is cached.