For the past few years, I\'ve developed client/server software using the Asynchronous Programming Model and sockets. This example on MSDN, although overcomplicated with synchron
Actually, the old APM supported by the Socket
class used a special thread pool, the IOCP ("I/O Completion Port") thread pool, and rather than assigning threads "when data is received", actually assigned threads as I/O operations are initiated, but in a way that allows a single thread (or small number of threads…e.g. as many as there are cores on the system) to handle a large number of socket objects and operations.
As far as how to use the new async
/await
style API, unfortunately the Socket
class didn't get any direct async
love. However, all of the wrappers did. The most straight-forward replacement is to use the NetworkStream
class, and use ReadAsync()
and WriteAsync()
, which are awaitable methods.
If you want to still use the Socket
API (essentially) directly, you'll have to wrap it yourself with an awaitable implementation. IMHO, a very good resource explaining one possible approach for doing this is here: Awaiting Socket Operations
The Task Asynchronous Pattern
and its used keywords async-await
lets you take use of async I/O (as you said) but in a "cleaner" fashion.
Instead of using BeginXXX
and EndXXX
methods and passing callbacks between each other, you can simply await
on an async method which returns an awaitable (A Task
is an example of one).
For example, lets make an example using HttpClient
:
public async Task DoGetWebRequestAsync()
{
var httpClient = new HttpClient();
await httpClient.GetAsync(url);
}
What this will do is once the method hits the await
keyword, it will yield control back to the calling method, creating a state-machine behind the scenes (which will be in charge of executing the continuation, propagating exceptions, etc..) and resume via an IOCP (IO Completion port, allocated by the ThreadPool) once the IO work is complete.
The TAP also offers a way to turn the old APM pattern into the TAP using TaskFactory.FromAsync:
FileInfo fi = new FileInfo(path);
byte[] data = null;
data = new byte[fi.Length];
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read,
FileShare.Read, data.Length, true);
//Task<int> returns the number of bytes read
Task<int> task = Task<int>.Factory.FromAsync(
fs.BeginRead, fs.EndRead, data, 0, data.Length, null);
Edit:
How to use async
is simple. For example, with FileStream
:
public async Task<byte[]> ReadBufferAsync(string path)
{
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read,
FileShare.Read, data.Length, true);
// Read some bytes, not all, just for the example.
byte[] buffer = new byte[2048];
await fs.ReadAsync(buffer, 0, buffer.Length);
return buffer;
}
You mark you method async
so you can use the await
keyword inside it, and then simply await
on the method which reads.