5 things you probably didn't know about .NET WebSockets
As most of you probably already know WebSocket provides full-duplex communication over a single TCP connection. .NET 4.5 added support for WebSockets as part of the BCL. In this article I am going to talk about few of the subtleties that you need to think about.
Connection upgrade is somewhat expensive WebSocket connections are initiated as traditional HTTP connections. The client then usually requests an “upgrade” to a WebSocket session, this upgrade process is relatively expensive. If you are interested in performance you may want to pool a set of connection that are already upgraded and use connections from the pool.
Simultaneous sends or receives While you can simultaneously do send and receive, you can only do one of each simultaneously. In other words at any given point in time you can only have a single pending send or a single pending receive. Various workaround exists for this limitation. For instance, SignalR uses a queue. The other option is to provide synchronizations using a ManualResetEvent - there are pros and cons to both so you need to think about what makes sense for your specific application.
Teardown There are two ways to close a WebSocket connection. The graceful way is CloseAsync which when initiated sends a message to the connected party, and waits for acknowledgement. The keyword here is sends. Remember in our previous point we discussed that you can only have a single send or receive at any given point in time? So if you are sending data, and at the same time try to CloseAsync this leads to an exception because CloseAsync will also try to send a message. The other option is to use CloseOutputAsync this is more of a “fire-and-forget” approach.
COM Exceptions? Based on some of our testing there are certain COM level exceptions that can happen during high load conditions. Once again if you look at the SignalR implementation you can treat these types of exceptions as non-fatal. 0x800703e3 - The I/O operation has been aborted because of either a thread exit or application request 0x800704cd - The remote host closed the connection 0x80070026 - Reached the end-of-file
Unobserved Exceptions Any unobserved exceptions (background thread exceptions that weren’t caught) can cause your WebSocket to get into an aborted state. This is because the .NET 4.5 implementation of WebSocket adds a TaskScheulder.UnobservedExceptions handler and aborts the connection for any exceptions that propagate up to it. So you have couple of choices here, first make sure that you don’t have unobserved exceptions (which means you have an issue that you are not even aware of). If you call any method that initiates a Task - make sure you store it and add a continuation to observe it’s exceptions. The other option is to add a TaskScheduler.UnobservedExceptions yourself to see what potential exceptions you are missing.