处事端的系统配置中常常会和底层协议打交道,我们有须要重温一下曾经那些“听过”却不熟悉的名词。 本日聊的话题是 KeepAlive,在实际应用中又是怎么利用的?
为什么有Keepalive?
各人都做过电梯吧,假设电梯来了你先进去,劳务派遣管理系统,你伴侣还没进来,过一段时间电梯门就会自动封锁, 你应该没碰着过哪个电梯会一直等你伴侣来了才关门的。假如然是那样,那此外楼层的小姐姐们会炸了~
我们举个编程中的例子来表明下,我编写了一个处事端措施S和一个客户端措施C,客户端向处事端发送 一个动静:
处事端收到动静后一看,劳务派遣管理系统,瞧给你牛*的,然后没理客户端,傻狗客户端一直在期待,可是不知道是不是处事器挂掉了? 这时候TCP协议提出一个步伐,当客户端端期待高出一按时间后自动给处事端发送一个空的报文, 假如对方回覆了这个报文证明毗连还存在世,假如对方没有报文返回且举办了多次实验都是一样,昆山软件开发, 那么就认为毗连已经丢失,客户端就没须要继承保持毗连了。 假如没有这种机制就会有许多空闲的毗连占用着系统资源。
KeepAlive并不是TCP协议类型的一部门,但在险些所有的TCP/IP协议栈(不管是Linux照旧Windows)中,都实现了KeepAlive成果
RFC1122#TCP Keep-Alives
如何配置它?
在配置之前我们先来看看KeepAlive都支持哪些配置项
我们讲讲在Linux操纵系统和利用Java、C语言和Nginx中如何配置
在Linux内核配置
KeepAlive默认不是开启的,假如想利用KeepAlive,需要在你的应用中配置SO_KEEPALIVE才可以生效。
查察当前的设置:
cat /proc/sys/net/ipv4/tcp_keepalive_time cat /proc/sys/net/ipv4/tcp_keepalive_intvl cat /proc/sys/net/ipv4/tcp_keepalive_probes
在Linux中我们可以通过修改 /etc/sysctl.conf 的全局设置:
net.ipv4.tcp_keepalive_time=7200 net.ipv4.tcp_keepalive_intvl=75 net.ipv4.tcp_keepalive_probes=9
添加上面的设置后输入 sysctl -p 使其生效,你可以利用 sysctl -a | grep keepalive 呼吁来查察当前的默认设置
假如应用中已经配置SO_KEEPALIVE,措施不消重启,内核直接生效
利用Netty4配置
这里我们利用常用的Java网络框架Netty来配置,只需要在处事端配置即可:
EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 100) .childOption(ChannelOption.SO_KEEPALIVE, true) .handler(new LoggingHandler(LogLevel.INFO)); // Start the server. ChannelFuture f = b.bind(8088).sync(); // Wait until the server socket is closed. f.channel().closeFuture().sync(); } finally { // Shut down all event loops to terminate all threads. bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); }
这段代码来自经典的echo处事器,我们在childOption中开启了SO_KEEPALIVE。 Java措施只能做到配置SO_KEEPALIVE选项,其他设置项只能依赖于sysctl设置,系统举办读取。
C语言配置
函数原型:
#include <sys/socket.h> int setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len);
我们在需要使能Keepalive的socket上面挪用setsockopt函数便可以打开该socket上面的keepalive。
挪用例子:
int socket(int domain, int type, int protocol) { int (*libc_socket)(int, int, int); int s, optval; char *env; *(void **)(&libc_socket) = dlsym(RTLD_NEXT, "socket"); if(dlerror()) { errno = EACCES; return -1; } if((s = (*libc_socket)(domain, type, protocol)) != -1) { if((domain == PF_INET) && (type == SOCK_STREAM)) { if(!(env = getenv("KEEPALIVE")) || strcasecmp(env, "off")) { optval = 1; } else { optval = 0; } if(!(env = getenv("KEEPALIVE")) || strcasecmp(env, "skip")) { setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)); } #ifdef TCP_KEEPCNT if((env = getenv("KEEPCNT")) && ((optval = atoi(env)) >= 0)) { setsockopt(s, SOL_TCP, TCP_KEEPCNT, &optval, sizeof(optval)); } #endif #ifdef TCP_KEEPIDLE if((env = getenv("KEEPIDLE")) && ((optval = atoi(env)) >= 0)) { setsockopt(s, SOL_TCP, TCP_KEEPIDLE, &optval, sizeof(optval)); } #endif #ifdef TCP_KEEPINTVL if((env = getenv("KEEPINTVL")) && ((optval = atoi(env)) >= 0)) { setsockopt(s, SOL_TCP, TCP_KEEPINTVL, &optval, sizeof(optval)); } #endif } } return s; }
代码摘取自libkeepalive源码,C语言可以配置更为具体的TCP内核参数
在Nginx中设置