如何阻止Kestrel与其他进程共享端口?
Kestrel端口冲突异常行为排查与解决方案需求
在Windows环境下,Kestrel与ASP.NET Core的端口冲突表现不符合预期,我需要实现:要么让应用正常监听端口,要么检测到冲突时立即记录错误并终止启动,避免出现应用看似运行但无法接收流量的情况。
具体场景:
- 我有一个用Kestrel搭建的ASP.NET Core站点,同时存在一个通过原生Socket(
new Socket(ipPoints[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp))监听80/443端口的控制台程序。 - 单独运行控制台程序时,执行
netstat -Aof | findstr LISTEN | findstr ":80 :443"能看到端口已被监听,浏览器可正常连接。 - 但在控制台程序运行时启动Kestrel站点,没有触发预期的端口占用错误,站点看似正常启动;再次执行netstat会发现两个进程都在监听同一端口。
- 反之,启动第二个Kestrel实例时,会正常抛出错误:
Unhandled exception. System.IO.IOException: Failed to bind to address https://[::]:443: address already in use.,这才是期望的行为。
实际问题:当其他进程占用端口时,Kestrel虽然显示运行,但完全无法接收流量,已有用户反馈应用"运行正常但无法访问",经查是第三方软件占用端口导致。我需要找到:
- 在Kestrel应用内阻止端口共享的方法,让它在检测到冲突时直接抛出错误
- 如果无法实现上述需求,也需要了解检测此类端口冲突的最佳实践
示例控制台程序
using System.Net; using System.Net.Sockets; using System.Linq; namespace PortListener { // 参考自Mohsan Saleem的Stack Overflow回答(原来源为MSDN) // 略有修改 class ListenPorts { private readonly Socket[] _socketConnections; private readonly IPEndPoint[] _ipPoints; internal ListenPorts(IPEndPoint[] ipPoints) { _ipPoints = ipPoints; _socketConnections = new Socket[ipPoints.Length]; } public void BeginListening() { for (var i=0;i<_ipPoints.Length;i++) { _socketConnections[i] = new Socket(_ipPoints[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp); _socketConnections[i].Bind(_ipPoints[i]); var thread = new Thread(ListenerThread); thread.Start(_socketConnections[i]); } } private static void ListenerThread(object? objs) { var socket = objs as Socket; var data = new byte[1024]; IPEndPoint sender; sender = socket.AddressFamily == AddressFamily.InterNetwork ? new IPEndPoint(IPAddress.Any, 0) : new IPEndPoint(IPAddress.IPv6Any, 0); EndPoint Remote = sender; try { socket.Listen(100); var newSocket = socket.Accept(); newSocket.ReceiveFrom(data, ref Remote); newSocket.Close(); } catch (SocketException ex) { Console.WriteLine(ex.Message); } Console.WriteLine($"{socket.LocalEndPoint} --> {Remote.ToString()}"); } } internal static class Program { private static void Main() { IPEndPoint[] ipPoints = { new (IPAddress.IPv6Any, 443), new (IPAddress.IPv6Any, 80), new (IPAddress.Any, 443), new (IPAddress.Any, 80), }; var portListener = new ListenPorts(ipPoints); portListener.BeginListening(); Console.WriteLine($"Now listening on \n{string.Join("\n", ipPoints.Select(x=>x.Address + " " + x.Port))}"); } } }
示例Kestrel应用
Program.cs
public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); webBuilder.UseUrls("https://mymachine.mydomain.com:443;http://mymachine.mydomain.com:80"); }); }
Startup.cs
public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); }); } }
内容的提问来源于stack exchange,提问作者Rob P.
相关产品推荐
相关产品推荐

