Connection refused after a while in a threaded process on tcp socket requests (c / linux)
I am trying to make a process that takes multiple requests every second, with every request a new thread is created. Each stream then opens a socket connection to the address (http port), sends HEAD requests, receives a response, and closes the socket.
The problem I am facing is when I put more than 3 requests per second, after a while I get an error in the send () function, I keep getting Connection Refused. If I enter more requests per second, I get errors sooner. If I only put 2 requests per second, I get no errors at all. I suspect I am running out of some resource, but I cannot find what.
Here is the basic structure of the 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 the beginning, which I get as a result: "Submit: Connection refused" after a while. I would appreciate some pointers on what might be causing the problem, the platform is ubuntu linux. I would also be happy to post other pieces of code if needed. Tnx in advance.
The resource that you are probably running out of is on the server you are connecting to. The connected computer is refused connection because it:
- Configure the connection per second limit (based on some criteria)
- Or the server you are connecting to is under too much load for some reason and cannot accept any additional connections.
Since you always get an error on the third connection, maybe the server you are connecting to is limiting the number of connections based on IP.
Edit1
Are you trying to make a non-blocking connection? Now when I look at it closer, it looks like your problem is with the selection, as the select returns that the socket is being read before it actually connects, and then you call send. One of the things to consider with non-blocking connections is that the socket becomes readable and is written on error. This means you need to check how after the return has been selected, otherwise you might miss any actual error and see the submission error.
This is from 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);
a source to share
There are quite a few problems in your code.
First, you set the socket to non-blocking. I don't understand why you are doing this. The connection function has an internal timeout and is therefore not blocked.
Another problem with your code is that the first if statement will skip the block of commands if the connection succeeds immediately! What can happen.
You obviously want to send a HEAD message first. There is no real need to block this blocking unless you expect the remote server or network to be very slow and want to spend time on it. In this case, a selection with a non-blocking socket will be accepted.
Once you send a HEAD message, you expect some data in return to be collected using the recv function. Be aware that this function call may return before all submitted data has been received. You need an independent way to determine that all submitted data has been received. Will the server close the connection? This is detected by the recv function returning 0.
So recv has to be wrapped in a loop where you append the received data to some buffer or file and terminate when recv returns 0. Use a non-blocking socket if you want to add a timeout to this recv operation, which can really block.
But try it without timeouts first to make sure it runs at full speed without blocking as the current version.
I suspect that the initial connection is slow due to name and IP resolution and speeds up on subsequent calls as the data is cached.
a source to share