es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

El puerto no se libera tan pronto como el programa sale en C# .NET Core.

Tengo una aplicación de consola C# .net core 3.1 que actúa como un servidor web REST. Se ejecuta como un servicio de Windows. Funciona bien, pero después de apagar la aplicación (o cuando se detiene durante una operación), no puedo iniciar la aplicación de inmediato. Recibo el siguiente error:

No se puede iniciar Kestrel. System.IO.IOException: Error al enlazar a la dirección http://[::]:8000: la dirección ya está en uso.

---> Microsoft.AspNetCore.Connections.AddressInUseException: Normalmente está permitido un solo uso de cada dirección de socket (protocolo/red/dirección/puerto).

--->System.Net.Sockets.SocketException(10048): Normalmente está permitido un solo uso de cada dirección de socket (protocolo/red/dirección/puerto).
.
.
.

Si intento después de unos 5 minutos aproximadamente, puedo iniciar la aplicación. ¿Hay algo que deba hacer o que pueda hacer para liberar la asignación en el puerto antes de detenerme en la aplicación?

Actualización – 1

Utilizo lo siguiente para apagar la aplicación en caso de errores, etc.

_hostLifetime.StopApplication();

Este es el código que inicializa el servidor web:

webBuilder.UseStartup<Startup>().UseUrls(restPort.Value);

El constructor de la clase Startup es el siguiente:

_httpListener = new HttpListener();

El método Configure en la clase Startup tiene el siguiente código:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseHttpsRedirection();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}
Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Parece que la aplicación no está liberando los recursos en el puerto cuando se detiene, lo que provoca el error “dirección ya en uso” al intentar iniciar la aplicación inmediatamente después de detenerla.

    Una solución podría ser detener explícitamente el servidor web antes de apagar la aplicación. Esto se puede hacer agregando un gancho en el evento de detención del servicio. En el archivo Program.cs, modifique el método CreateHostBuilder para agregar el evento de detención de esta manera:

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseWindowsService()
            .ConfigureServices((hostContext, services) =>
            {
                services.AddHostedService<worker>();
                services.AddSingleton<iserviceprovider>(sp => services.BuildServiceProvider());
    
                var webHost = Host.CreateDefaultBuilder(args)
                    .ConfigureWebHostDefaults(webBuilder =>
                    {
                        webBuilder.UseStartup<startup>().UseUrls(restPort.Value);
                    })
                    .Build();
    
                // vincule el evento de detención para liberar el servidor web
                hostContext.ApplicationLifetime.ApplicationStopping.Register(() =>
                {
                    webHost.StopAsync(TimeSpan.FromSeconds(5)).GetAwaiter().GetResult();
                    webHost.Dispose();
                });
            });
    

    Esto debería asegurarse de que el servidor web se detenga correctamente antes de que la aplicación se apague, liberando los recursos en el puerto.

    Otra opción es capturar la excepción AddressInUseException en el archivo Program.cs y volver a intentar iniciar la aplicación después de un retraso, de esta manera:

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseWindowsService()
            .ConfigureServices((hostContext, services) =>
            {
                services.AddHostedService<worker>();
                services.AddSingleton<iserviceprovider>(sp => services.BuildServiceProvider());
    
                var webHostBuilder = Host.CreateDefaultBuilder(args)
                    .ConfigureWebHostDefaults(webBuilder =>
                    {
                        webBuilder.UseStartup<startup>().UseUrls(restPort.Value);
                    });
    
                // agregue un mecanismo de reintento para iniciar el servidor web
                int retryCount = 0;
                const int maxRetryCount = 5;
                TimeSpan retryDelay = TimeSpan.FromSeconds(5);
                webHostBuilder.ConfigureKestrel(options =>
                {
                    options.Listen(IPAddress.Any, 8000, listenOptions =>
                    {
                        listenOptions.UseConnectionLogging();
                        listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
                    });
                });
                var webHost = webHostBuilder.Build();
                while (retryCount < maxRetryCount)
                {
                    try
                    {
                        webHost.Start();
                        break;
                    }
                    catch (AddressInUseException)
                    {
                        // espera un retraso antes de volver a intentar iniciar la aplicación
                        Thread.Sleep(retryDelay);
                        retryCount++;
                    }
                }
            });
    

    Este enfoque agrega un mecanismo de reintento para iniciar el servidor web, esperando un retraso antes de volver a intentar iniciar si el puerto ya está en uso. El número máximo de intentos y el retraso se pueden configurar según los requisitos de la aplicación.

Comments are closed.