Socket.ConnectAsync 对于 windows 商店应用程序不喜欢异步
Socket.ConnectAsync for windows store application does not like Async
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
一起使用。
我对使用原始套接字的人的第一条建议是 "don't"。如果可以,请使用 REST API(使用 HttpClient
)或 SignalR
API。原始套接字有很多陷阱。
如果您必须使用原始套接字(即,另一方正在使用自定义 TCP/IP 协议,而您无权修复这种情况) , 那么首先要注意的是 Socket
class 三个完整的 API 合而为一 class.
第一个是看似简单的同步 API (Connect
),我不推荐将其用于任何生产代码。第二个是标准的 APM 模式 (BeginConnect
/EndConnect
)。第三种是专门针对Socket
class(ConnectAsync
)的异步模式;这个专用的 API 比标准的异步 API 使用起来复杂得多,只有当您在受限环境中进行繁琐的套接字通信并且需要通过垃圾收集器减少对象流失时才有必要。
请注意,没有 await
兼容的 API。我没有和微软的任何人谈过这件事,但我强烈怀疑他们只是认为 Socket
class 已经有太多成员(3 个完整的 API;添加一个 await
-compatible 将添加第四个完整的 API),这就是为什么当他们将 TAP 模式(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);
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
一起使用。
我对使用原始套接字的人的第一条建议是 "don't"。如果可以,请使用 REST API(使用 HttpClient
)或 SignalR
API。原始套接字有很多陷阱。
如果您必须使用原始套接字(即,另一方正在使用自定义 TCP/IP 协议,而您无权修复这种情况) , 那么首先要注意的是 Socket
class 三个完整的 API 合而为一 class.
第一个是看似简单的同步 API (Connect
),我不推荐将其用于任何生产代码。第二个是标准的 APM 模式 (BeginConnect
/EndConnect
)。第三种是专门针对Socket
class(ConnectAsync
)的异步模式;这个专用的 API 比标准的异步 API 使用起来复杂得多,只有当您在受限环境中进行繁琐的套接字通信并且需要通过垃圾收集器减少对象流失时才有必要。
请注意,没有 await
兼容的 API。我没有和微软的任何人谈过这件事,但我强烈怀疑他们只是认为 Socket
class 已经有太多成员(3 个完整的 API;添加一个 await
-compatible 将添加第四个完整的 API),这就是为什么当他们将 TAP 模式(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);