我有一个服务器来从不同的客户端收集 Tcp数据到某个端口。我有一个场景,每当客户端创建tcp连接并保持空闲超过让我们说30分钟,那么我需要关闭连接。
我已经了解了 TCP keep alive 来跟踪对等体是否已经死亡,而且我发现客户端使用的示例大多数情况。同样,我可以在服务器端使用它来轮询连接是否处于活动状态?
此外,在 linux sysctl.conf 中,有一个用于编辑值的配置文件。这似乎是在某些不活动之后整个tcp连接被破坏。我需要这样,设备的某些连接会在一段时间不活动后被销毁,但不会关闭整个tcp端口连接。
我正在使用 ubuntu 创建服务器以收集tcp连接。我可以在服务器代码中使用 TCP Keep-Alives 来查找非活动客户端并关闭特定客户端吗?或者在服务器端有没有其他方法来实现这样的功能?
并且在浏览网页时提到了
(getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen)
这个getsockopt用于主tcp连接,设置似乎是设置是与服务器的整个连接。
然而,我需要的是特定的客户。我有事件服务器代码 此处 client_fd 已被接受,现在如果在一定时间内未收到通过此客户端的下一个数据,我需要关闭此client_fd。
void event_server(EV_P_ struct ev_io *w, int revents) {
int flags;
struct sockaddr_in6 addr;
socklen_t len = sizeof(addr);
int client_fd;
// since ev_io is the first member,
// watcher `w` has the address of the
// start of the _sock_ev_serv struct
struct _sock_ev_serv* server = (struct _sock_ev_serv*) w;
server->socket_len = len;
for (;;) {
if ((client_fd = accept(server->fd, (struct sockaddr*) &addr, &len)) < 0) {
switch (errno) {
case EINTR:
case EAGAIN:
break;
default:
zlog_info(_c, "Error accepting connection from client \n");
//perror("accept");
}
break;
}
char ip[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &addr.sin6_addr, ip, INET6_ADDRSTRLEN);
char *dev_ip = get_ip(ip);
server->device_ip = dev_ip;
zlog_debug(_c,"The obtained ip is %s and dev_ip is %s", ip, dev_ip);
/** check for the cidr address for config_ip **/
char *config_ip;
config_ip = get_config_ip(dev_ip, _client_map);
zlog_debug(_c,"The _config ip for dev_ip:%s is :%s", dev_ip, config_ip);
if (config_ip == NULL) {
zlog_debug(_c,"Connection attempted from unreigistered IP: %s", dev_ip);
zlog_info(_c, "Connection attempted from unregistered IP : %s", dev_ip);
AFREE(server->device_ip);
continue;
}
json_t *dev_config;
dev_config = get_json_object_from_json(_client_map, config_ip);
if (dev_config==NULL) {
zlog_debug(_c,"Connection attempted from unreigistered IP: %s", dev_ip);
zlog_info(_c, "Connection attempted from unregistered IP : %s", dev_ip);
AFREE(server->device_ip);
continue;
}
if ((flags = fcntl(client_fd, F_GETFL, 0)) < 0 || fcntl(client_fd, F_SETFL, flags | O_NONBLOCK) < 0) {
zlog_error(_c, "fcntl(2)");
}
struct _sock_ev_client* client = malloc(sizeof(struct _sock_ev_client));
client->device_ip = dev_ip;
client->server = server;
client->fd = client_fd;
// ev_io *watcher = (ev_io*)calloc(1, sizeof(ev_io));
ev_io_init(&client->io, event_client, client_fd, EV_READ);
ev_io_start(EV_DEFAULT, &client->io);
}
}
答案 0 :(得分:1)
TCP keep alives不会检测空闲客户端,而是检测死连接,即如果客户端在没有关闭连接的情况下崩溃或者线路已经死亡等等。但是如果客户端只是空闲但没有死,则连接仍然是打开的。任何尝试向客户端发送空数据包(保持活动数据包)将导致来自客户端的ACK,因此保持活动状态不会报告死连接。
要检测空闲客户端,请使用超时读取(SO_RCVTIMEO)或使用select,poll或类似功能的超时。
答案 1 :(得分:-1)
我已经实现了以下机制来检测Socket
IO活动的空闲状态。
我的Socket
包含在某些类UserConnection
中。该类还有一个属性lastActivtyTime
。每当我对此Socket
进行读写操作时,我都会更新此属性。
我还有一个后台Reaper
线程,它将迭代所有UserConnection
个对象并检查lastActivtyTime。 如果当前时间 - lastActivtyTime大于配置的阈值参数(如15秒 ),我将关闭空闲连接。
在您的情况下,当您遍历所有UserConnections
时,您可以检查 client_id 以及 30分钟不活动的阈值 关闭空闲连接。