Для интеграции `TcpListener` в фоновый сервис `BackgroundService` в ASP.NET Web API вы можете использовать асинхронные методы, которые позволяют лучше управлять потоками и более эффективно обрабатывать входящие подключения. Ваши примеры кода в целом правильны, но их можно оптимизировать и сделать более читаемыми.
Вот улучшенный пример, как можно реализовать `TcpListener` с использованием `BackgroundService`. Обратите внимание, что мы будем использовать цикл обработки клиентов, при этом будем следить за флагом отмены (`cancellationToken`):
```csharp
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
public class TcpServerService : BackgroundService
{
private readonly ILogger<TcpServerService> _logger;
private TcpListener _listener;
public TcpServerService(ILogger<TcpServerService> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_listener = new TcpListener(IPAddress.Any, 4000); // Используйте необходимый порт
_listener.Start();
_logger.LogInformation("TCP Server started, waiting for connections...");
try
{
while (!stoppingToken.IsCancellationRequested)
{
var client = await _listener.AcceptTcpClientAsync(stoppingToken);
_logger.LogInformation("Client connected.");
_ = HandleClientAsync(client, stoppingToken);
}
}
catch (SocketException socketEx)
{
_logger.LogError("SocketException: {Message}", socketEx.Message);
}
catch (Exception ex)
{
_logger.LogError("General Exception: {Message}", ex.Message);
}
finally
{
_listener.Stop();
_logger.LogInformation("TCP Server stopped.");
}
}
private async Task HandleClientAsync(TcpClient client, CancellationToken stoppingToken)
{
using (client)
{
var buffer = new byte[1024];
var stream = client.GetStream();
int bytesRead;
try
{
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, stoppingToken)) != 0)
{
var message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
_logger.LogInformation($"Received message: {message}");
// Здесь можно добавить логику обработки сообщения, например, отправить ответ
var response = $"Echo: {message}";
var data = Encoding.UTF8.GetBytes(response);
await stream.WriteAsync(data, 0, data.Length, stoppingToken);
}
}
catch (Exception ex)
{
_logger.LogError("Exception while handling client: {Message}", ex.Message);
}
}
}
}
```
### Объяснение кода:
1. **TcpListener**: Мы создаем `TcpListener`, который будет слушать заданный порт.
2. **Непрерывное ожидание подключений**: Внутри метода `ExecuteAsync` мы запускаем бесконечный цикл, который ожидает подключения. Он использует `AcceptTcpClientAsync` с передачей токена отмены для правильного выхода из цикла в случае отмены сервиса.
3. **Обработка клиентов**: Для каждого подключенного клиента мы вызываем метод `HandleClientAsync`, который получает данные и может обрабатывать их. Это позволяет освободить основной поток для ожидания новых подключений.
4. **Логирование**: Включено логирование для отслеживания событий и возможных ошибок, что очень полезно при отладке.
### Заключение
Данный подход делает ваш TCP сервер более устойчивым и читаемым и предотвращает проблемы, связанные с завершением работы при получении исключений. Этот сервис будет работать в фоновом режиме и обрабатывать клиентские соединения асинхронно, не блокируя основное приложение.