Reputation: 8494
I've designed a class which wraps a Socket
and allows sending and receiving through/from it. Since accepting, sending and receiving are done through the UI, I don't want them to block it thus I used their asynchronous versions.
Here's the relevant code:
public void Accept()
{
// ...
// where resultAccept is a IAsyncResult
resultAccept = listener.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
private void AcceptCallback(IAsyncResult ar)
{
connectedSocket = listener.EndAccept(ar);
}
public string Receive()
{
char[] data = new char[128];
if (!resultAccept.IsCompleted) // (1)
resultAccept.AsyncWaitHandle.WaitOne();
connectedSocket.BeginReceive(Encoding.UTF8.GetBytes(data), 0, data.Length, SocketFlags.None,
new AsyncCallback(RecvCallback), null);
// ...
}
When I start receiving, since there's no connection yet, it has to wait for one (1) and blocks the UI (which, again, I don't want).
In addition, when a connection is accepted I get a NullReferenceException
because when BeginReceive
starts, AcceptCallback
is, yes triggered, but has not completed yet so connectedSocket
still has to be initialized.
Upvotes: 1
Views: 846
Reputation: 171178
Socket
extension methods on the web that adapt the obsolete APM pattern to the TAP pattern so that you can use await. The exercise becomes trivial then.Your code should look like:
async Task RunServer() {
Socket serverSocket = ...;
while (true) {
RunConnection(await serverSocket.AcceptAsync());
}
}
And then provide a Task RunConnectionAsync(Socket s)
function that is async as well. Really simple once you leave the obsolete APM pattern alone.
Alternatively, just use threads and synchronous IO. Nothing wrong with doing that. await
is a little nicer, though, because it marshals back to the UI thread for you automatically.
Upvotes: 1