我正在实现一个客户端服务器TCP套接字应用程序。Client
在OpenWRT Linux路由器(基于C)上,并以一定的频率反复地将一些数据写在套接字上并成环。它Server
位于Linux Ubuntu计算机(基于C / C ++)上,并根据数据到达速度循环读取数据。
问题:运行Server
and之后Client
,服务器将继续读取新数据。双方合作很好,直到数据交付的数量(连接#)达到1013之后,Client
停留在socket(AF_INET,SOCK_STREAM,0)
用socket creation failed...: Too many open files
。显然,客户开放fd
方法的数量ulimit -n = 1024
。
我把代码片段显示为Server.cpp
和的循环结构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);
}
}
}
注意:payload
是,800 bytes
并且始终会在一write
动作中完全传输。在定义了这两个代码之后int main()
,客户端将继续创建套接字并发送数据,而另一方面close()
,由于使用,服务器将接收所有信息并自动接收并在客户端终止时退出select()
。Client
但是,如果我没有通过检查一些打印日志来终止,则很明显Server
在客户端崩溃之前,成功接收了1013个有效负载socket creation failed...: Too many open files
。
更新:
遵循Steffen Ullrich提到的观点,事实证明,客户端套接字fd
没有泄漏,并且fd
原始循环(保持打开状态)中存在第二秒ulimit
超出了限制。
if(read(sock, &res, sizeof(res)) < 0){
serverOff = true;
close(sock); /********* Not actually closing sock *********/
}
您的连接终止检查不正确。
read
如果另一方已关闭连接且<0
仅在发生错误时返回0 。
if (sock = socket(AF_INET, SOCK_STREAM, 0) == -1)
perror("socket creation failed...\n");
sock = ( socket(AF_INET, SOCK_STREAM, 0) == -1) )
if (sock) ...
假设socket(...)
不会返回错误而是返回一个文件描述符(即>=0
),则比较将为false,因此,sock = 0
如果返回的fd为socket
was,则这实际上在泄漏文件描述符时表示>0
。
我已经尝试过
=
,并<
作为read(sock, &res, sizeof(res)) <= 0)
,但在结果没有变化。当我打印时read
,它显示-1
。这个小循环while
始终会成功传递,否则它将永远陷入其中。@zlg:在这种情况下
close
应调用。您确定代码中的某处没有使用其他文件描述符,并且这些描述符实际上正在泄漏(您没有显示完整的代码,所以无法分辨)?就像已经在评论中说的那样,如果connect
失败,肯定是泄漏。@zlg:您的代码还有更多问题,请参阅更新的答案。或者您显示的代码不是您使用的实际代码,在这种情况下,尝试在其中查找问题的任何尝试都是没有用的。
这实际上是一个好点。没有其他套接字,但是我在整个代码中处理了一个日志记录(1400行),应该仔细检查
fopen
fclose
该单个文件上的所有匹配项。但是,即使发生这种情况,也一定会在socket()
创作中成为问题吗?@zlg:对套接字没有限制,但通常对文件描述符没有限制。套接字和常规文件,管道,目录句柄..都是文件描述符,并受此限制。例如,
lsof -p process_id
您可以查看当前正在使用哪些文件描述符以及它们的用途。