使用.NetCore在Linux上写TCP listen 重启后无法绑定地址

简介: 拥抱.net core的过程中, 将公司的一套java项目改成了.net core 2.0版的. 里面的tcp服务被我用msdn的SocketAsyncEventArgs方式重写了, 然而在测试的过程中发现, 偶尔会出现重启无法再次绑定监听的情况.

拥抱.net core的过程中, 将公司的一套java项目改成了.net core 2.0版的.

里面的tcp服务被我用msdn的SocketAsyncEventArgs方式重写了, 然而在测试的过程中发现, 偶尔会出现重启无法再次绑定监听的情况.

因为缺乏linux上编程的经验, 对linux的认识过于粗浅, 仅凭现有的知识第一反应是, 是不是在asp.net core的结束时没有清理干净, 也不是呀, 在lifetime中记录了日志都清楚地打印了.

打开搜索引擎, 搜linux下socket绑定失败, 找到一条似乎有用的答案, socket options设置reuse address为true.

有道理, 于是在绑定前加了一条: 

listener.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.ReuseAddress, true);

并没有什么软用...

于是打算借鉴下开源项目中的做法. 翻了下supersocket, 发现尚未有支持netcore版, 于是跳过. 又翻了下dotnetty, 发现开始监听和结束两处都没什么区别. 

突然想到asp.net core本身不就是能正常重启监听吗? 那看源码吧, 对了是Kestrel的源码, 于是GitHub, download, 简单搜索之后看到如下函数:

        [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

目录
相关文章
|
7天前
|
存储 NoSQL Linux
linux积累-core文件是干啥的
核心文件是Linux系统在程序崩溃时生成的重要调试文件,通过分析核心文件,开发者可以找到程序崩溃的原因并进行调试和修复。本文详细介绍了核心文件的生成、配置、查看和分析方法
34 6
|
9天前
|
存储 NoSQL Linux
linux之core文件如何查看和调试
通过设置和生成 core 文件,可以在程序崩溃时获取详细的调试信息。结合 GDB 等调试工具,可以深入分析 core 文件,找到程序崩溃的具体原因,并进行相应的修复。掌握这些调试技巧,对于提高程序的稳定性和可靠性具有重要意义。
48 6
|
5月前
|
安全 Linux 调度
在Linux中,如何实现,每星期天早8点服务器定时重启?
在Linux中,如何实现,每星期天早8点服务器定时重启?
|
5月前
|
存储 Ubuntu Linux
在Linux中,如何查看当前主机的主机名,如何修改主机名?要想重启后依旧生效,需要修改哪个配置文件?
在Linux中,如何查看当前主机的主机名,如何修改主机名?要想重启后依旧生效,需要修改哪个配置文件?
|
2月前
|
Linux 数据库
Linux服务如何实现服务器重启后的服务延迟自启动?
【10月更文挑战第25天】Linux服务如何实现服务器重启后的服务延迟自启动?
351 3
|
3月前
|
网络协议 Linux 网络性能优化
Linux C/C++之TCP / UDP通信
这篇文章详细介绍了Linux下C/C++语言实现TCP和UDP通信的方法,包括网络基础、通信模型、编程示例以及TCP和UDP的优缺点比较。
64 0
Linux C/C++之TCP / UDP通信
|
3月前
|
网络协议 Linux 开发工具
linux系统配置固定地址
linux系统配置固定地址
|
3月前
|
网络协议 Linux 网络性能优化
Linux基础-socket详解、TCP/UDP
综上所述,Linux下的Socket编程是网络通信的重要组成部分,通过灵活运用TCP和UDP协议,开发者能够构建出满足不同需求的网络应用程序。掌握这些基础知识,是进行更复杂网络编程任务的基石。
191 1
|
5月前
|
移动开发 监控 网络协议
在Linux中,如何查看 http 的并发请求数与其 TCP 连接状态?
在Linux中,如何查看 http 的并发请求数与其 TCP 连接状态?
|
5月前
|
监控 网络协议 Linux
在Linux中,如何实时抓取并显示当前系统中tcp 80 端口的网络数据信息?
在Linux中,如何实时抓取并显示当前系统中tcp 80 端口的网络数据信息?