C# network sockets vs C++ Win32 IOCP

Sat 20 June 2015 | tags: 103
I spend a lot of time working on low level network protocols for proprietary hardware, and I normally use Win32 IOCP in C++. But a few projects must be implemented in C# for business reasons, and so I've spent a some time implementing nearly equivalent code in the .NET Framework. I figured it's time to write up my favorite C# solutions so far.

Option 1: EVAP (event-based asynchronous pattern) with Nito Async Sockets. I had an excellent discussion with Stephen Cleary last year about asynchronous socket operations last year, and he convinced me to try his library. I've used it on several large projects now, and I really like it. It makes callbacks painless because Nito automatically marshalls into the original (i.e. GUI) thread.

Having said that, I can do the same thing in C++ with only a little more effort using IOCP. Using a background thread to call GetQueuedCompletionStatus and then using PostMessage to get to the GUI thread via a standard window message queue isn't really that hard. I agree that it requires more code, which means more opportunities for errors, but it's almost equivalent to what the the .NET Framework is doing, which requires more overhead. Some people have complained about slower speed for high throughput servers with the C# approach, and my experience supports the fact that even the best practices in C# will always be slower than the C++ options.

Option 2: await NetworkStream.ReadAsync and WriteAsync (only in .NET 4.5 or newer). I really like this solution for some specific network protocols. These methods allow all the benefits of simple async / await implementations without having to write a Task-based wrapper and handle a bunch of edge cases with Exceptions. If you can't target .NET 4.5, then you're stuck with writing wrappers for Socket.BeginReceive and Socket.BeginWrite and related methods. I'd go back to using EVAP before using the Begin/End pairs because it's easy to leak kernel resources if you don't catch all the Exceptions in EndReceive.

In C++, there isn't anything like async / await, but you can fake it. If you read up on how async is implemented, it is just an automatically generated finite state machine applied to a transformed version of the original C# code. It's a really powerful compiler trick, but I have to write FSMs anyway for my programs, so I incorporate the socket events into a larger FSM for the other state transitions in the program. I'll grant that it's a pain to handle both synchronous and asynchronous completions of WSARecv because it doubles the number of state transitions (must check for WSA_IO_PENDING, must free the OVERLAPPED structure only after the IO has posted on the IOCP, etc.). But it's still doable. I've done worse. Don't judge me! :P

Option 3: Rxx (Extensions for Reactive Extensions) with
FromAsyncPattern. OK, I admit I haven't actually tried this approach yet, and I've found a lot of skeptical discussion about it. It looks like it might work, but it's as convoluted as anything else I've ever seen with EVAP or await based code. I'm not convinced that I can debug it yet (debugging is twice as hard as writing the code in the first place).

In conclusion: I'm sticking with EVAP until Stephen Cleary finds a way to make Rx with sockets tolerable or until I can install .NET 4.5 on more of my target machines at work.

blogroll