我使用AddHttpClient()
依赖注入将命名客户端添加到临时服务。有时,当我在服务器上执行netstat -a
时,我看到许多连接处于TIME_WAIT
或CLOSE_WAIT
状态。我相信这些连接占用了大量资源,其他TCP
连接无法运行。这可能吗?有什么方法可以阻止这些安全吗?
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
ServicePointManager.DefaultConnectionLimit = 200;
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddHttpClient(FirebaseService.FirebaseServiceClient, ConfigureFirebaseClient);
services.AddTransient<FirebaseService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc();
}
void ConfigureFirebaseClient(HttpClient client)
{
var scopes = new string[] { "https://www.googleapis.com/auth/firebase.messaging" };
Stream certificateStream = File.OpenRead("firebase-adminsdk.json");
var serviceCredentials = GoogleCredential.FromStream(certificateStream);
certificateStream.Close();
var scopedCredentials = serviceCredentials.CreateScoped(scopes);
var token = scopedCredentials.UnderlyingCredential.GetAccessTokenForRequestAsync().GetAwaiter().GetResult();
client.SetBearerToken(token);
}
}
public class FirebaseService
{
public static string FirebaseServiceClient = "FirebaseServiceClient";
private HttpClient _client;
private readonly ILogger<FirebaseService> _logger;
private readonly string _messagingUrl;
public FirebaseService(
ILogger<FirebaseService> logger,
IHttpClientFactory clientFactory)
{
_logger = logger;
_messagingUrl = "https://fcm.googleapis.com/v1/projects/test2/messages:send";
_client = clientFactory.CreateClient(FirebaseServiceClient);
}
public async Task<string> PostToFirebase(Dictionary<string, string> payload)
{
HttpResponseMessage result = null;
string cont = null;
try
{
var content = JsonConvert.SerializeObject(payload, Formatting.None);
var stringContent = new StringContent(content, Encoding.UTF8, "application/json");
result = await _client.PostAsync(_messagingUrl, stringContent);
cont = await result.Content.ReadAsStringAsync();
return cont;
}
finally
{
result?.Dispose();
}
}
}
public class ValuesController : ControllerBase
{
private readonly IServiceProvider _serviceProvider;
public ValuesController(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
[HttpGet]
public async Task<IActionResult> Get()
{
var payload = new Dictionary<string, string>();
List<Task> tasks = new List<Task>();
for (int i = 0; i < 100; i++)
{
FirebaseService firebaseService = (FirebaseService)_serviceProvider.GetService(typeof(FirebaseService));
var task = firebaseService.PostToFirebase(payload);
tasks.Add(task);
Console.WriteLine(i);
}
await Task.WhenAll(tasks.ToArray());
//Console.WriteLine(result);
return Ok();
}
}
答案 0 :(得分:0)
CLOSE_WAIT-另一端关闭了连接。
TIME_WAIT-本地端点(您的应用程序)关闭了连接。
两个连接都保留几分钟,以防万一对方有一些延迟的数据包。
“我相信这些连接占用了太多资源,其他TCP连接无法运行。这可能吗?” - 我觉得不是。他们只是保持打开端口。这取决于有多少个。如果你有几百个,你会没事的。
“有没有一种方法可以阻止这些危险,安全吗?” -我不这么认为。它们都具有相同的PID,因此,如果您尝试杀死一个,则所有应用程序都将关闭。
期待更好的答案。
答案 1 :(得分:0)
我意识到遇到问题的联系并非源自client.PostAsync()
。实际上,它们来自IHttpClientFactory的“客户端配置”操作中的firebase令牌身份验证请求。这就是为什么当我切换到单例或静态属性时,CreateClient(clientName)
并没有被多次调用,并且问题消失了的原因。尽管这是清楚地写在文档中的,但我还是错过了。 Each time CreateClient is called, a new instance of HttpClient is created and the configuration action is called.
答案 2 :(得分:-2)
好吧,因为您可能使用了错误的生命周期管理方法。 HttpClient存在套接字耗尽问题,因此,如果可能,应将其作为单例使用。
此article 将回答您的问题。另请enter link description here阅读有关DNS更改的解决方法。