I am implementing a client-server TCP socket application. Client
is on an OpenWRT Linux router (C based) and writes some data on the socket repeatedly and in a loop at some frequency rate. The Server
is on a Linux Ubuntu machine (C/C++ based) and reads data in a loop according to data arrival speed.
Problem: Running the Server
and then Client
, server keeps reading new data. Both sides work well until the number of data deliveries (# of connections) reaches 1013. After that, the Client
stuck at socket(AF_INET,SOCK_STREAM,0)
with socket creation failed...: Too many open files
. Apparently, the number of open fd
approaches ulimit -n = 1024
on client.
I put the snippets of the code which shows the loop structures for Server.cpp
and Client.c
:
Server.c:
// TCP Socket creation stuff over here (work as they should):
// int sock_ = socket() / bind() / listen()
while (1)
{
socklen_t sizeOfserv_addr = sizeof(serv_addr_);
fd_set set;
struct timeval timeout;
int connfd_;
FD_ZERO(&set);
FD_SET(sock_, &set);
timeout.tv_sec = 10;
timeout.tv_usec = 0;
int rv_ = select(sock_ + 1, &set, NULL, NULL, &timeout);
if(rv_ == -1){
perror("select");
return 1;
}
else if(rv_ == 0){
printf("Client disconnected.."); /* a timeout occured */
close (connfd_);
close (sock_);
}
else{
connfd_ = accept (sock_,(struct sockaddr*)&serv_addr_,(socklen_t*)&sizeOfserv_addr);
if (connfd_ >= 0) {
int ret = read (connfd_, &payload, sizeof(payload)); /* some payload */
if (ret > 0)
printf("Received %d bytes !\n", ret);
close (connfd_); /* Keep parent socket open (sock_) */
}else{
printf("Server acccept failed..\n");
close (connfd_);
close (stcp.sock_);
return 0;
}
}
}
Client.cpp:
while (payload_exist) /* assuming payload_exist is true */
{
struct sockaddr_in servaddr;
int sock;
if (sock = socket(AF_INET, SOCK_STREAM, 0) == -1)
perror("socket creation failed...\n");
int one = 1;
int idletime = 2;
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one));
setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &idletime, sizeof(idletime));
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("192.168.100.12");
servaddr.sin_port = htons(PORT); /* some PORT */
if (connect (sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) != 0){
perror("connect failed...");
return 1;
}
write(sock, (struct sockaddr*)&payload, sizeof(payload)); /* some new payload */
shutdown(sock,SHUT_WR);
bool serverOff = false;
while (!serverOff){
if(read(sock, &res, sizeof(res)) < 0){
serverOff = true;
close(sock);
}
}
}
NOTE: payload
is 800 bytes
and always gets fully transmitted per one write
action. Having both codes defined under int main()
, the client keeps creating sockets and sending data, on the other side, server receives all and would automatically close()
and leave if client terminates, due to using select()
. If I don't terminate the Client
, however, by checking some print logs, it is evident that Server
successfully receives 1013 payloads before client crashes with socket creation failed...: Too many open files
.
Update:
Following the point mentioned by Steffen Ullrich, it turned out that, the client socket fd
has no leak, and the existence of a second fd
in the original loop (which was left open) was making the ulimit
exceed the limit.
if(read(sock, &res, sizeof(res)) < 0){
serverOff = true;
close(sock); /********* Not actually closing sock *********/
}
Your check for end of connection is wrong.
read
returns 0 if the other side has shut down the connection and <0
only on error.
if (sock = socket(AF_INET, SOCK_STREAM, 0) == -1)
perror("socket creation failed...\n");
Given the precedence of operators in C this basically says:
sock = ( socket(AF_INET, SOCK_STREAM, 0) == -1) )
if (sock) ...
Assuming that socket(...)
will not return an error but a file descriptor (i.e. >=0
) the comparison will be false and thus this essentially says sock = 0
while leaking a file descriptor if the fd returned by socket
was >0
.
I already tried
=
and<
asread(sock, &res, sizeof(res)) <= 0)
, yet no change in result. When I print theread
, it shows-1
. That smallwhile
loop always gets passed successfully, as otherwise it will stuck in that for ever.@zlg: In this case
close
should be called. Are you sure that there are no other file descriptors used somewhere in your code and that these are actually leaking (you don't show the full code, so impossible to tell)? And as said in a comment already, it is definitely leaking if theconnect
fails.@zlg: And there are more problems with your code, see updated answer. OR the code you show is not the actual code you use in which case any attempts to find the problem in it are useless.
That's actually a good point. There is no other socket, but I also handle one log fine throughout the code (which is 1400 lines) and should carefully check all the
fopen
fclose
matchings on that single file. But, even if that happens, will it necessarily become an issue within thesocket()
creation ?@zlg: There is no limit on sockets but on file descriptors in general. Sockets and regular files, pipes, directory handles .. are all file descriptors and subject to this limit. For example with
lsof -p process_id
you can see what file descriptors are currently in use and what they are used for.