Windows应用商店应用程序的Socket.ConnectAsync不喜欢异步

时间:2015-12-28 01:20:16

标签: 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似乎支持等待......

不支持等待吗?

1 个答案:

答案 0 :(得分:6)

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

对于任何使用原始套接字的人来说,我的第一推荐是“不要”#34;。如果可以,请使用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模式(await兼容的)成员添加到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);