c# - Windows 应用商店应用程序的 Socket.ConnectAsync 不喜欢 Async

标签 c# windows-store-apps async-await

至少可以说,Windows 商店应用程序令人沮丧;与常规 .net 足够接近就会惹上麻烦。

我在使用 Tasks、await 和 Socket.ConnectAsync 时遇到的问题。

我有以下代码:

    public async Task<string> Connect(string hostName, int portNumber)
    {
        string result = string.Empty;

        // Create DnsEndPoint. The hostName and port are passed in to this method.
        DnsEndPoint hostEntry = new DnsEndPoint(hostName, portNumber);

        // Create a stream-based, TCP socket using the InterNetwork Address Family. 
        _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        // Create a SocketAsyncEventArgs object to be used in the connection request
        SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
        socketEventArg.RemoteEndPoint = hostEntry;

        // Inline event handler for the Completed event.
        // Note: This event handler was implemented inline in order to make this method self-contained.
        socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate (object s, SocketAsyncEventArgs e)
        {
            // Retrieve the result of this request
            result = e.SocketError.ToString();

            // Signal that the request is complete, unblocking the UI thread
            _clientDone.Set();
        });

        // Sets the state of the event to nonsignaled, causing threads to block
        _clientDone.Reset();

        // Make an asynchronous Connect request over the socket
        await _socket.ConnectAsync(socketEventArg);

        // Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
        // If no response comes back within this time then proceed
        _clientDone.WaitOne(TIMEOUT_MILLISECONDS);

        return result;
    }

我开始在应用程序中添加 Async/await 以防止出现 UI 问题。但是当我进入这个函数并将 Await 添加到

            await _socket.ConnectAsync(socketEventArg);

我得到错误:

错误 CS1929 'bool' 不包含 'GetAwaiter' 的定义,最佳扩展方法重载 'WindowsRuntimeSystemExtensions.GetAwaiter(IAsyncAction)' 需要类型为 'IAsyncAction' 的接收器

在查看 ConnectAsync 的文档时,看起来 ConnectAsync 应该支持 await...

不支持await吗?

最佳答案

不,ConnectAsync 不是 TAP method ,因此不能与 await 一起使用。

我对任何使用原始套接字的人的第一条建议是“不要”。如果可以,请使用 REST API(使用 HttpClient)或 SignalR API。原始套接字有很多陷阱。

如果您必须使用原始套接字(即,另一端正在使用自定义 TCP/IP 协议(protocol),而您无权修复这种情况),那么首先要注意的是是 Socket 类在一个类中具有三个完整的 API。

第一个是看似简单的同步 API (Connect),我不推荐将其用于任何生产代码。第二种是标准的 APM 模式 (BeginConnect/EndConnect)。第三种是特定于Socket 类的专用异步模式(ConnectAsync);这个专门的 API 使用起来比标准的异步 API 复杂得多,只有当您在受限环境中进行繁琐的套接字通信并且需要通过垃圾收集器减少对象流失时才有必要。

请注意,没有与 await 兼容的 API。我没有和微软的任何人谈过这件事,但我强烈怀疑他们只是认为 Socket 类已经有太多成员(3 个完整的 API;添加一个 await-compatible 会添加第四个完整的 API),这就是为什么当他们将 TAP-pattern (await-compatible) 成员添加到 BCL 中的其他类型时,它被跳过了。

要使用的正确 API(在 99.999% 的情况下很容易)是 APM API。你可以create your own TAP wrappers (which work with await) by using TaskFactory.FromAsync .我喜欢用扩展方法来做到这一点,就像这样:

public static Task ConnectTaskAsync(this Socket socket, EndPoint remoteEP)
{
  return Task.Factory.FromAsync(socket.BeginConnect, socket.EndConnect, remoteEP, null);
}

然后您可以在 Socket 上的任何位置调用它,如下所示:

await _socket.ConnectTaskAsync(hostEntry);

关于c# - Windows 应用商店应用程序的 Socket.ConnectAsync 不喜欢 Async,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34486638/

相关文章:

c# - rx里面有没有ThrottleOrMax之类的东西?

c# - 将此字符串转换为日期时间对象

c# - Windows 应用商店应用程序 - XAML - C# - 在代码中访问 ThemeResource

c# - 在共享的 WinRT 8.1 页面上显示广告

c# - 处理异步异常

c# - 使用 log4net 记录时“等待”不返回 UI 线程

c# - Asp.Net Core 未找到 DefaultChallengeScheme

c# - 静态与实例方法用法

windows-8 - Windows 8 应用商店应用

c# - 在简单的自定义同步上下文中,异步、等待的线程峰值数量