用于windows存储应用程序的Socket.ConnectAsync不喜欢Async

本文关键字:ConnectAsync 不喜欢 Async Socket windows 存储 应用程序 用于 | 更新日期: 2023-09-27 18:28:08

Windows商店应用程序至少令人沮丧;刚好接近常规的.net,以免惹上麻烦。

我在任务、等待和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"的定义。GetAwaiteer(IAsyncAction)"需要类型为"IAsyncAction"的接收器

在查看ConnectAsync的文档时,看起来ConnectAsync应该支持等待。。。

它不支持等待吗?

用于windows存储应用程序的Socket.ConnectAsync不喜欢Async

否,ConnectAsync不是TAP方法,因此不能与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将添加第四个完整的API),这就是为什么当他们将TAP-pattern(await兼容)成员添加到BCL中的其他类型时,它被跳过了。

正确使用的API(99.999%的时间都可以轻松使用)是APM。您可以使用TaskFactory.FromAsync创建自己的TAP包装器(可与await一起使用)。我喜欢用扩展方法来做这件事,比如:

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

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

await _socket.ConnectTaskAsync(hostEntry);