拥抱.net core的过程当中, 将公司的一套java项目改为了.net core 2.0版的.java
里面的tcp服务被我用msdn的SocketAsyncEventArgs方式重写了, 然而在测试的过程当中发现, 偶尔会出现重启没法再次绑定监听的状况.linux
由于缺少linux上编程的经验, 对linux的认识过于粗浅, 仅凭现有的知识第一反应是, 是否是在asp.net core的结束时没有清理干净, 也不是呀, 在lifetime中记录了日志都清楚地打印了.git
打开搜索引擎, 搜linux下socket绑定失败, 找到一条彷佛有用的答案, socket options设置reuse address为true.github
有道理, 因而在绑定前加了一条: 编程
listener.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.ReuseAddress, true);
并无什么软用...asp.net
因而打算借鉴下开源项目中的作法. 翻了下supersocket, 发现还没有有支持netcore版, 因而跳过. 又翻了下dotnetty, 发现开始监听和结束两处都没什么区别. socket
忽然想到asp.net core自己不就是能正常重启监听吗? 那看源码吧, 对了是Kestrel的源码, 因而GitHub, download, 简单搜索以后看到以下函数:tcp
[DllImport("libc", SetLastError = true)] private static extern int setsockopt(int socket, int level, int option_name, IntPtr option_value, uint option_len); private const int SOL_SOCKET_OSX = 0xffff; private const int SO_REUSEADDR_OSX = 0x0004; private const int SOL_SOCKET_LINUX = 0x0001; private const int SO_REUSEADDR_LINUX = 0x0002; // Without setting SO_REUSEADDR on macOS and Linux, binding to a recently used endpoint can fail. // https://github.com/dotnet/corefx/issues/24562 private unsafe void EnableRebinding(Socket listenSocket) { var optionValue = 1; var setsockoptStatus = 0; if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { setsockoptStatus = setsockopt(listenSocket.Handle.ToInt32(), SOL_SOCKET_LINUX, SO_REUSEADDR_LINUX, (IntPtr)(&optionValue), sizeof(int)); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { setsockoptStatus = setsockopt(listenSocket.Handle.ToInt32(), SOL_SOCKET_OSX, SO_REUSEADDR_OSX, (IntPtr)(&optionValue), sizeof(int)); } if (setsockoptStatus != 0) { _trace.LogInformation("Setting SO_REUSEADDR failed with errno '{errno}'.", Marshal.GetLastWin32Error()); } }
真相大白. socket option 设置reuse address便可.函数
而后解释上面代码的注释里也给出了, 在这里:测试
https://github.com/dotnet/corefx/issues/24562