【发布时间】:2020-05-17 10:41:02
【问题描述】:
我正在实现一个客户端-服务器 TCP 套接字应用程序。 Client 位于 OpenWRT Linux 路由器(基于 C)上,并以某种频率重复在套接字上写入一些数据并循环写入。 Server在Linux Ubuntu机器上(基于C/C++),根据数据到达速度循环读取数据。
问题:运行Server,然后运行Client,服务器不断读取新数据。双方工作良好,直到数据传递的数量(连接数)达到 1013。之后,Client 卡在socket(AF_INET,SOCK_STREAM,0) 和socket creation failed...: Too many open files。显然,在客户端打开fd 的数量接近ulimit -n = 1024。
我放了代码的 sn-ps,它显示了 Server.cpp 和 Client.c 的循环结构:
服务器.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;
}
}
}
客户端.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 在客户端因socket creation failed...: Too many open files 而崩溃之前成功接收了1013 个有效负载。
更新:
按照 Steffen Ullrich 提到的观点,事实证明,客户端套接字 fd 没有泄漏,并且在原始循环中存在第二个 fd(保持打开状态)正在使 @987654345 @超出限制。
【问题讨论】:
-
我确定
close总是会关闭 Linux 上的套接字。 -
您应该在调用
close()时检查返回码。 -
你确定它没有关闭袜子吗?
close(sock);does 是否有可能关闭 sock 但那行代码实际上并没有运行?也许connect失败了,因此套接字没有关闭?如果服务器正常关闭,最后一个循环(serverOff)将是一个无限循环,因为 read 返回 0。 -
^^^^ 上面肯定会泄露一个描述符。如果
connect失败,你就盲目地返回,留下一个打开的套接字描述符。 -
@user253751 @WhozCraig,假设服务器永远不会首先终止,而是客户端。用户将终止
Client,这将使Server在超时后关闭。好吧,在 1013 条消息之后,我再也没有收到perror(connect failed)的回报。它只返回perror(socket creation failed)。我认为connect()在客户端工作得很好。