asp.net 如何防止与Kestrel共享端口?

3lxsmp7m  于 11个月前  发布在  .NET
关注(0)|答案(1)|浏览(121)

在我的Windows机器上,我很难理解Kestrel和asp.net核心与机器上其他进程的端口冲突的行为。我想防止Kestrel和另一个进程都侦听同一个端口的情况。
我有一个使用Kestrel的应用程序,我希望它要么监听,要么检测冲突并记录错误消息。
我还有一个小型的控制台应用程序,它使用套接字在与我的Kestrel应用程序(80和443)相同的端口上侦听(new Socket(ipPoints[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp))。
从运行netstat -Aof | grep LISTEN | grep ':80\s\|:443\s'输出的控制台应用程序开始显示:

TCP    0.0.0.0:80             mymachine.mydomain.com:0  LISTENING       53172
  TCP    [::]:80                mymachine.mydomain.com:0  LISTENING       53172
  TCP    0.0.0.0:443            mymachine.mydomain.com:0  LISTENING       53172  
  TCP    [::]:443               mymachine.mydomain.com:0  LISTENING       53172

字符串
我可以打开Web浏览器并查看与控制台应用程序建立的连接。
当这个程序还在运行时,我启动了我的asp.net核心网站。我本以为会出现某种错误,但它似乎工作正常。重复netstat命令,我看到两个进程现在都在以完全相同的方式侦听。
netstat -Aof | grep LISTEN | grep ':80\s\|:443\s'显示:

TCP    0.0.0.0:80             mymachine.mydomain.com:0  LISTENING       53172
  TCP    [::]:80                mymachine.mydomain.com:0  LISTENING       53172
  TCP    0.0.0.0:443            mymachine.mydomain.com:0  LISTENING       53172  
  TCP    [::]:443               mymachine.mydomain.com:0  LISTENING       53172                             
  TCP    0.0.0.0:80             mymachine.mydomain.com:0  LISTENING       19728
  TCP    [::]:80                mymachine.mydomain.com:0  LISTENING       19728
  TCP    0.0.0.0:443            mymachine.mydomain.com:0  LISTENING       19728  
  TCP    [::]:443               mymachine.mydomain.com:0  LISTENING       19728


奇怪的是,如果我运行我的Kestrel应用程序两次,第二次将失败,并出现以下错误:
未处理的异常。System.IO.IOException:无法绑定到地址https://[::]:443:地址已在使用中。
这是我希望看到的行为。但是当它不是kestrel的第二个示例时,它只是使用端口的其他东西,我似乎可以让kestrel运行和侦听,但不接收流量。
我只是分发Kestrel应用程序。我们收到一个用户的报告说:“应用程序正在运行,日志文件中没有错误,您提供的状态工具说一切正常,但当我转到http://example.com时,没有加载任何内容”
我知道我们无法控制用户的环境,并且总是有可能发生错误配置的东西或其他东西,以阻止我的应用程序按预期运行,但我想给予用户最好的体验。
有没有办法在我的Kestrel应用程序中阻止这种类型的端口共享,或者让Kestrel在发生这种情况时抛出错误?如果没有,有没有检测这些冲突的最佳实践方法?

控制台应用示例

using System.Net;
using System.Net.Sockets;

namespace PortListener
{
    // Borrowed from SO Mohsan Saleem's answer (which was borrowed from MSDN answer
    // https://stackoverflow.com/a/52361311/73381
    // Slightly updated
    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 + " -->  {0}: ", 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();
        });
    }
}

slhcrj9b

slhcrj9b1#

问题出在您的控制台应用程序中,而不是Kestrel中。您的应用程序在独占模式下不侦听,因此Kestrel也可以侦听端口。将Socket.ExclusiveAddressUse设置为true(在Windows上测试,没有Unix ATM的设置):

public void BeginListening()
{
    for (var i=0;i<_ipPoints.Length;i++)
    {
        _socketConnections[i] = new Socket(_ipPoints[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp);
        _socketConnections[i].ExclusiveAddressUse = true;
        // ...
    }
}

字符串

相关问题