【问题标题】:Socket.ConnectAsync for windows store application does not like AsyncWindows 商店应用程序的 Socket.ConnectAsync 不喜欢 Async
【发布时间】:2015-12-28 01:20:16
【问题描述】:

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...

不支持等待吗?

【问题讨论】:

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


    【解决方案1】:

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

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

    如果您必须使用原始套接字(即,对方正在使用自定义 TCP/IP 协议,而您没有能力解决这种情况),那么首先要注意是Socket类在一个类中拥有三个完整的API。

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

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

    要使用的正确 API(在 99.999% 的情况下很容易使用)是 APM。你可以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);
    

    【讨论】:

    • 很遗憾,我没有连接到 REST API(很遗憾)。 Windows Store API 很难找到工作(可行)的类。我不知道 signalR 可以使用它;我会看看它,看看它是否适合我正在做的事情。谢谢,斯蒂芬。
    • @DaBlue:实际上是Socket 类以这种方式很奇怪。在桌面框架上也有同样的问题。
    • 我对信号器抱有希望,但这不会奏效。我将我写的一个类拉到通用窗口中(我有一些转换要做)只是为了弄清楚它不会连接到不是信号服务器的套接字。我现在正在研究流套接字。
    • 使用 Core (netcoreapp1.0) 我无法找到公共 socket.BeginConnect。 net451 中存在结构。假设我缺少一个依赖项。
    • @MatthewYoung:很有趣。 netcore 上的It looks like Socket 仅支持SocketAsyncEventArgs API。不过有TAP wrappers available - 我就用那些。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-21
    • 1970-01-01
    相关资源
    最近更新 更多