Я пишу ConnectionHandler
как часть Kestrel. Идея состоит в том, что при подключении клиента ConnectionHandler
открывает сокет с другим сервером в сети, получает непрерывный поток данных и перенаправляет их обратно клиенту. Тем временем клиент также может отправлять данные на ConnectionHandler
, который последний постоянно пересылает на другой сервер в сети (открытый сокет).
public override async Task OnConnectedAsync(ConnectionContext connection)
{
TcpClient serverSocket = TcpClient(address, port);
serverSocket.ReceiveTimeout = 10000;
serverSocket.SendTimeout = 10000;
NetworkStream dataStream = serverSocket.GetStream();
dataStream.ReadTimeout = 10000;
dataStream.WriteTimeout = 10000;
Stream clientStreamOut = connection.Transport.Output.AsStream();
Stream clientStreamIn = connection.Transport.Input.AsStream();
Task dataTask = Task.Run(async () =>
{
try
{
await dataStream.CopyToAsync(clientStreamOut);
}
catch
{
await LogsHelper.Log(logStream, LogsHelper.BROKEN_CLIENT_STREAM);
return;
}
}, connection.ConnectionClosed);
Task clientTask = Task.Run(async () =>
{
try
{
await clientStreamIn.CopyToAsync(dataStream);
}
catch
{
await LogsHelper.Log(logStream, LogsHelper.BROKEN_DATA_STREAM);
return;
}
}, connection.ConnectionClosed);
await Task.WhenAny(dataTask, clientTask);
}
Я столкнулся с 3 проблемами:
- Для сокета с другим сервером я использую
TcpClient
, а я NetworkStream
. Даже если для ReadTimeout
и WriteTimeout
установлено значение 10 секунд, для TcpClient
и NetworkStream
открытый сокет ожидает бесконечно, даже если другой сервер в сети не отправляет данные в течение 5 минут. . - Установка таймаута для
clientStreamOut
и clientStreamIn (e.g: clientStreamIn.ReadTimeout = 10000;)
также не удалась, за исключением того, что она не поддерживается для этого конкретного потока. Мне было интересно, можно ли как-то предоставить тайм-аут? - Когда клиент подключается к
ConnectionHandler
, OnConnectedAsync
срабатывает. Проблема с кодом возникает, когда клиент отключается (из-за сбоя сети или по любой другой причине). Иногда обнаруживается отключение клиента, и сеанс завершается, в то время как в других случаях он навсегда зависает, даже если клиент фактически был отключен. Я ожидал, что CopyToAsync
выдаст исключение в случае разъединения, так как я предполагаю, что CopyToAsync
пытается записать, но это не всегда случай.
connection.ConnectionClosed
- это CancellationToken
от OnConnectedAsync
, я прочитал здесь https://github.com/dotnet/runtime/issues/23207, что его можно использовать в CopyToAsync
. Однако я не уверен, как я могу это использовать. Также стоит отметить, что у меня нулевой контроль над клиентским кодом.
Я запускаю приложение, используя Docker
FROM mcr.microsoft.com/dotnet/core/sdk:3.1
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1