C # Настройка WriteTimeout / ReadTimeout в сетевом потоке не имеет значения? - PullRequest
0 голосов
/ 21 февраля 2019

У меня следующий код метода в приложении Xamarin.Forms

using (TcpClient client = new TcpClient(ip, port))
using (NetworkStream stream = client.GetStream())
{
    byte[] messageBytes = PrepareMessageBytes();

    //
    // Setting these seam to have no effect
    //
    stream.WriteTimeout = (int)TimeSpan.FromSeconds(10).TotalMilliseconds;
    stream.ReadTimeout = (int)TimeSpan.FromSeconds(10).TotalMilliseconds;

    //
    // I have set read and write timeouts above but when 
    // hitting this line, app hangs indefinitely?  
    // I would expect that after 10 seconds, a IOException
    // will be thrown
    await stream.WriteAsync(messageBytes, 0, messageBytes.Length);
    stream.Flush();

    byte[] buffer = new byte[1024];
    StringBuilder builder = new StringBuilder();
    int bytesRead = 0;

    while (stream.DataAvailable)
    {
        bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
        builder.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, bytesRead));
    }

    string msg = receivedMessage.ToString();
} 

Выше я установил тайм-ауты для записи и чтения на 10 секунд.Я знаю, что мой код зависает при вызове:

await stream.WriteAsync (...)

, но я ожидаю, что через 10 секунд будет сгенерировано исключение IOException.Основываясь на документации MS, это не относится к асинхронным операциям записи / чтения.

Как установить тайм-аут для вызовов методов WriteAsync / ReadAsync?

ОБНОВЛЕНИЕ - 2-Й ПОПЫТКА, ОСНОВАННАЯ НАКОММЕНТАРИЙ СТЕФЕНА

Основываясь на комментарии Стивена, я обновил код и включил его в try..catch для обработки исключения OperationCancelledException. Но это вызывает еще больше проблем, чем раньше, и приложение по-прежнему будет зависать большую часть времени :

try
{
    using (TcpClient client = new TcpClient(ip, port))
    using (NetworkStream stream = client.GetStream())
    using (var writeCts = new CancellationTokenSource(TimeSpan.FromSeconds(10)))
    {
        byte[] messageBytes = PrepareMessageBytes();

        await stream.WriteAsync(messageBytes, 0, messageBytes.Length, writeCts.Token);
        await stream.FlushAsync();

        byte[] buffer = new byte[1024];
        StringBuilder builder = new StringBuilder();
        int bytesRead = 0;

        while (stream.DataAvailable)
        {
            using (var readCts = new CancellationTokenSource(TimeSpan.FromSeconds(10)))
                bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, readCts.Token);
            builder.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, bytesRead));
        }

        string msg = receivedMessage.ToString();
    }
catch (OperationCancelledException ex)
{
    Debug.WriteLine(ex.Message);
}

1 Ответ

0 голосов
/ 22 февраля 2019

Как установить время ожидания для вызовов методов WriteAsync / ReadAsync?

Вы используете перегрузку, которая принимает параметр CancellationToken:

using (TcpClient client = new TcpClient(ip, port))
using (NetworkStream stream = client.GetStream())
using (var writeCts = new CancellationTokenSource(TimeSpan.FromSeconds(10)))
{
    byte[] messageBytes = PrepareMessageBytes();

    await stream.WriteAsync(messageBytes, 0, messageBytes.Length, writeCts.Token);
    await stream.FlushAsync();

    byte[] buffer = new byte[1024];
    StringBuilder builder = new StringBuilder();
    int bytesRead = 0;

    while (stream.DataAvailable)
    {
        using (var readCts = new CancellationTokenSource(TimeSpan.FromSeconds(10)))
            bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, readCts.Token);
        builder.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, bytesRead));
    }

    string msg = receivedMessage.ToString();
}

Я ожидаю, что через 10 секунд будет сгенерировано исключение IOException.

При использовании токенов отмены ожидайте OperationCanceledException.Технически токены отмены можно использовать для самых разных сценариев отмены: код решает, что больше не нужно завершать операцию, пользователь вручную отменил операцию или произошел тайм-аут.OperationCanceledException - это общий тип исключения, означающий «отменено».

...