SslStream.WriteAsync“当另一个写操作未决时,不能调用BeginWrite方法". [英] SslStream.WriteAsync "The BeginWrite method cannot be called when another write operation is pending"

查看:119
本文介绍了SslStream.WriteAsync“当另一个写操作未决时,不能调用BeginWrite方法".的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在异步将数据异步写入客户端时防止此问题

How to prevent this issue when writing data to the client Asynchronously

The BeginWrite method cannot be called when another write operation is pending

MYCODE

public async void Send(byte[] buffer)
{
    if (buffer == null)
        return;
    await SslStream.WriteAsync(buffer, 0, buffer.Length);
}

推荐答案

准确了解await关键字的作用很重要:

It is important to understand exactly what the await keyword does:

await表达式不会阻塞它所在的线程 执行.相反,它会导致编译器签署其余的 异步方法作为已完成任务的延续.然后控制 返回到异步方法的调用者.任务完成后, 调用其继续,并恢复执行异步方法 停止的位置( MSDN-等待(C#参考)).

An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off (MSDN - await (C# Reference)).

调用带有非空缓冲区的发送时,您将进入

When you call Send with some non null buffer you will get to

    await SslStream.WriteAsync(buffer, 0, buffer.Length);

使用等待仅在Send方法中阻止执行,但是即使WriteAsync尚未完成,调用方中的代码仍继续执行.现在,如果在WriteAsync完成之前再次调用Send方法,则您将收到已发布的异常,因为SslStream不允许进行多次写入操作,并且已发布的代码也不会阻止这种情况的发生.

Using await you block the execution only in the Send method, but the code in the caller continues to execute even if the WriteAsync has not completed yet. Now if the Send method is called again before the WriteAsync has completed you will get the exception that you have posted since SslStream does not allow multiple write operations and the code that you have posted does not prevent this from happening.

如果要确保以前的BeginWrite已完成,则必须更改Send方法以返回Task

If you want to make sure that the previous BeginWrite has completed you have to change the Send method to return a Task

    async Task Send(SslStream sslStream, byte[] buffer)
    {
        if (buffer == null)
            return;

        await sslStream.WriteAsync(buffer, 0, buffer.Length);
    }

,然后使用await调用它,以等待其完成:

and wait for it's completion by calling it using await like:

    await Send(sslStream, message);

如果您不尝试从多个线程写入数据,这应该可以工作.

This should work if you do not attempt to write data from multiple threads.

这也是一些代码,可防止来自多个线程的写入操作重叠(如果与您的代码正确集成).它使用中间队列和异步编程模型(APM),并且运行速度非常快. 您需要调用EnqueueDataForWrite来发送数据.

Also here is some code that prevents write operations from multiple threads to overlap (if properly integrated with your code). It uses an intermediary queue and the Asynchronous Programming Model(APM) and works quite fast. You need to call EnqueueDataForWrite to send the data.

    ConcurrentQueue<byte[]> writePendingData = new ConcurrentQueue<byte[]>();
    bool sendingData = false;

    void EnqueueDataForWrite(SslStream sslStream, byte[] buffer)
    {
        if (buffer == null)
            return;

        writePendingData.Enqueue(buffer);

        lock (writePendingData)
        {
            if (sendingData)
            {
                return;
            }
            else
            {
                sendingData = true;
            }
        }

        Write(sslStream);            
    }

    void Write(SslStream sslStream)
    {
        byte[] buffer = null;
        try
        {
            if (writePendingData.Count > 0 && writePendingData.TryDequeue(out buffer))
            {
                sslStream.BeginWrite(buffer, 0, buffer.Length, WriteCallback, sslStream);
            }
            else
            {
                lock (writePendingData)
                {
                    sendingData = false;
                }
            }
        }
        catch (Exception ex)
        {
            // handle exception then
            lock (writePendingData)
            {
                sendingData = false;
            }
        }            
    }

    void WriteCallback(IAsyncResult ar)
    {
        SslStream sslStream = (SslStream)ar.AsyncState;
        try
        {
            sslStream.EndWrite(ar);
        }
        catch (Exception ex)
        {
            // handle exception                
        }

        Write(sslStream);
    }

这篇关于SslStream.WriteAsync“当另一个写操作未决时,不能调用BeginWrite方法".的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆