最近在写一个在Linux上运行的.netcore的网络底层库,踩到Socket KeepAlive的坑,记录一下。
————————
.net core有两个api可以设定socket的KeepAlive:IOControl
和SetSocketOption
。
IOControl
public int IOControl (System.Net.Sockets.IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue);
optionInvalue字段可以设置KeepAlive的详细参数
但是只在Windows下生效,Linux运行到这段代码会直接抛出不支持的异常,这点在API文档里并没有详细提及,如果想要设定KeepAlive,就只能使用SetSocketOption
SetSocketOption
SetSocketOption有几个重载的函数
public void SetSocketOption (System.Net.Sockets.SocketOptionLevel optionLevel, System.Net.Sockets.SocketOptionName optionName, bool optionValue);
public void SetSocketOption (System.Net.Sockets.SocketOptionLevel optionLevel, System.Net.Sockets.SocketOptionName optionName, byte[] optionValue);
public void SetSocketOption (System.Net.Sockets.SocketOptionLevel optionLevel, System.Net.Sockets.SocketOptionName optionName, int optionValue);
参考IOControl
的用法,我想当然的使用带有byte[] optionValue
参数的函数,但是使用wireshark抓包时发现这并不生效……
github的dotnet源码库下,也有一些关于这个问题的issue,比如:
Setting keepalivetime and keepaliveinterval on Linux Sockets
TCP_KEEPALIVE, TCP_KEEPINTVL, and TCP_KEEPCNT Socket Options
*跨平台的坑还挺大的,dotnet core任重道远,开发者谨慎一点 *
其中有个人指出2.2版本已经修复了这个问题?
Add cross-platform support for keep-alive socket options
我把版本上调到2.2,发现文中提及的TcpKeepAliveRetryCount
、TcpKeepAliveTime
和TcpKeepAliveInterval
依然没有,虽然在github上能看到对应提交,也不知道是为什么
修改Linux内核的keepalive参数
.netcore 2.1和2.2都没有找到很好的方式来设定keepalive参数,Linux默认的探测报文时间太长,对于游戏服务器来说几乎没什么用,目前来说只能修改Linux的默认探测报文参数了
vim /etc/sysctl.conf
添加或修改以下值
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_intvl = 10
net.ipv4.tcp_keepalive_probes = 10
执行sysctl -p
命令使修改生效
总结
- 跨平台的坑还是挺大的,在开发环境写到某个节点后,一定要在正式运行环境测试一下
- 幸亏没有偏听偏信(百度出来的代码) ,使用wireshark抓包测了一下keep-alive的设置,才知道在Linux下是无效的,自己的验证很重要!
- 为了解决这个问题,百度了很久,绕了很多弯路,以后首选Google…
- 持续关注一下这个api,看一下后面的版本是否解决了这个问题