首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何为async-await调用创建包装器?

如何为async-await调用创建包装器?
EN

Stack Overflow用户
提问于 2011-02-16 01:26:05
回答 3查看 2.2K关注 0票数 7

据我所知,没有对ConnectAsync/AcceptAsync/SendAsync/ReceiveAsync,等的内置(或框架扩展)支持。我如何编写自己的包装器来支持异步等待机制。例如,我当前处理内联和回调(在SocketAsyncEventArgs中指定)的ReceiveAsync的代码:

代码语言:javascript
复制
private void PostReceive(SocketAsyncEventArgs e)
{       
    e.SetBuffer(ReceiveBuffer.DataBuffer, ReceiveBuffer.Count, ReceiveBuffer.Remaining);            
    e.Completed += Receive_Completed;

            // if ReceiveAsync returns false, then completion happened inline
    if (m_RemoteSocket.ReceiveAsync(e) == false)
    {
        Receive_Completed(this, e);
    }                          
}

代码语言:javascript
复制
private void Receive_Completed(object sender, SocketAsyncEventArgs e)
{   
    e.Completed -= Receive_Completed;       

    if (e.BytesTransferred == 0 || e.SocketError != SocketError.Success)
    {
        if (e.BytesTransferred > 0)
        {                   
            OnDataReceived(e);
        }

        Disconnect(e);                
        return;
    }

    OnDataReceived(e);

    //
    // we do not push the SocketAsyncEventArgs back onto the pool, instead
    // we reuse it in the next receive call
    //
    PostReceive(e);
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-02-16 01:32:41

诀窍是使用TaskCompletionSource来处理这种情况。

我在博客上提到了这一点。详情请参见Preparing Existing code For Await

票数 3
EN

Stack Overflow用户

发布于 2012-09-04 05:51:12

你也可以写一个自定义的awaitable,在这种情况下我更喜欢它。这是微软的Stephen Toub的一项技术。你可以在这里阅读更多关于这项技术的内容。http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx

以下是可等待的自定义:

代码语言:javascript
复制
public sealed class SocketAwaitable : INotifyCompletion
{
    private readonly static Action SENTINEL = () => { };
    internal bool m_wasCompleted;
    internal Action m_continuation;
    internal SocketAsyncEventArgs m_eventArgs;
    public SocketAwaitable(SocketAsyncEventArgs eventArgs)
    {
        if (eventArgs == null) throw new ArgumentNullException("eventArgs");
        m_eventArgs = eventArgs;
        eventArgs.Completed += delegate
        {
            var prev = m_continuation ?? Interlocked.CompareExchange(
                ref m_continuation, SENTINEL, null);
            if (prev != null) prev();
        };
    }
    internal void Reset()
    {
        m_wasCompleted = false;
        m_continuation = null;
    }
    public SocketAwaitable GetAwaiter() { return this; }
    public bool IsCompleted { get { return m_wasCompleted; } }
    public void OnCompleted(Action continuation)
    {
        if (m_continuation == SENTINEL ||
            Interlocked.CompareExchange(
                ref m_continuation, continuation, null) == SENTINEL)
        {
            Task.Run(continuation);
        }
    }
    public void GetResult()
    {
        if (m_eventArgs.SocketError != SocketError.Success)
            throw new SocketException((int)m_eventArgs.SocketError);
    }
}

将一些扩展方法添加到socket类中,使其更加方便:

代码语言:javascript
复制
public static class SocketExtensions
{
    public static SocketAwaitable ReceiveAsync(this Socket socket,
        SocketAwaitable awaitable)
    {
        awaitable.Reset();
        if (!socket.ReceiveAsync(awaitable.m_eventArgs))
            awaitable.m_wasCompleted = true;
        return awaitable;
    }
    public static SocketAwaitable SendAsync(this Socket socket,
        SocketAwaitable awaitable)
    {
        awaitable.Reset();
        if (!socket.SendAsync(awaitable.m_eventArgs))
            awaitable.m_wasCompleted = true;
        return awaitable;
    }
    // ... 
}

使用中:

代码语言:javascript
复制
    static async Task ReadAsync(Socket s)
    {
        // Reusable SocketAsyncEventArgs and awaitable wrapper 
        var args = new SocketAsyncEventArgs();
        args.SetBuffer(new byte[0x1000], 0, 0x1000);
        var awaitable = new SocketAwaitable(args);

        // Do processing, continually receiving from the socket 
        while (true)
        {
            await s.ReceiveAsync(awaitable);
            int bytesRead = args.BytesTransferred;
            if (bytesRead <= 0) break;

            Console.WriteLine(bytesRead);
        }
    }
票数 2
EN

Stack Overflow用户

发布于 2012-09-04 06:03:08

对于套接字的东西,.NET 4.5中有一个包装器。如果您使用的是APM4,我建议您使用.NET,而不是基于事件的异步模式。它转换成Task要容易得多。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5007106

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档