So I was attempting to make use of IO completion ports and build a high performance socket server in C# by making use of the *Async methods such as ReceiveAsync with SocketAsyncEventArgs. However I’ve encountered a problem which I cannot seem to find a solution for which involves a StackOverException being triggered by the execution of these methods. You see, at first glance everything appeared to be humming along nicely, until I decided to flood my server with about 12,000 randomly sized packets. That’s when the problem shows up.
I have a TryReceive method that makes the first call to ReceiveAsync, and if it returns FALSE, then I call the ProcessReceive directly, otherwise it gets called by the Completed event getting invoked on the SocketAsyncEventArgs. ProcessReceive then does some processing of the message and then calls TryReceive to start the process all over again. For whatever reason, the ReceiveAsync is always completing synchronously and creating a recursive loop with my two methods.
I’m not really sure what to try at this point, other than possibly trying to call it on another thread, but I’m worried that might cause some other recursive thread call issues. If anyone has any ideas feel free to hit up my contact form.
Here’s some extracted snippets of code to show how the calls are structured.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
private void TryReceive() { ... if (!Socket.ReceiveAsync(_receiveEventArg)) ProcessReceive(_receiveEventArg); ... } private void OnAsyncCompleted(object sender, SocketAsyncEventArgs e) { // Determine which type of operation just completed and call the associated handler switch (e.LastOperation) { case SocketAsyncOperation.Receive: ProcessReceive(e); break; case SocketAsyncOperation.Send: ProcessSend(e); break; default: throw new ArgumentException("The last operation completed on the socket was not a receive or send"); } } private void ProcessReceive(SocketAsyncEventArgs e) { ... if (e.SocketError == SocketError.Success) { // If zero is returned from a read operation, the remote end has closed the connection if (size > 0) TryReceive(); else Disconnect(); } } ... } |