在我的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();
});
}
}
型
1条答案
按热度按时间slhcrj9b1#
问题出在您的控制台应用程序中,而不是Kestrel中。您的应用程序在独占模式下不侦听,因此Kestrel也可以侦听端口。将
Socket.ExclusiveAddressUse
设置为true
(在Windows上测试,没有Unix ATM的设置):字符串