Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><code>Socket.Receive</code> seems to have an upper limit on the <code>ReceiveTimeout</code> of two minutes. This is something that is supposedly specified in the registry, though I could find no concrete evidence of either the truth of this or the keys to modify. This might explain the different behaviour on Linux vs Windows.</p> <p>I looked into various solutions for this, but the simplest (and only one that worked) is probably to have the server end send a heartbeat every few seconds. Essentially, this just makes sure that you never hit the two minute timeout.</p> <pre><code>string boundary = string.Format("--{0}--", Guid.NewGuid()); byte[] boundaryBytes = Encoding.ASCII.GetBytes(boundary); //Every 15 seconds write a byte to the stream. for (int i = 0; i &lt; 10; i++) { stream.WriteByte(0); Thread.Sleep(15000); } //Indicate where the end of the heartbeat bytes is. stream.Write(boundaryBytes, 0, boundaryBytes.Length); //Same code as before. try { stream.Write(responseBytes, 0, responseBytes.Length); } catch (SocketException ex) { Console.WriteLine("Socket exception in server: {0}", ex.Message); } </code></pre> <p>What I've done here is simulate a long running task (it will sleep for 2.5 minutes in total), but every 15 seconds it writes a single byte to the stream to prevent the timeout.</p> <p>The problem with doing this is that you wind up with a bunch of unwanted garbage at the beginning of the response. This is where the <code>boundaryBytes</code> come in: with these you can clearly separate the unwanted bits from the actual result. The important thing is that the client <strong>must</strong> be aware of what the boundary is up front.</p> <p><strong>Edit:</strong></p> <p>I see from your comment below that removing the <code>socket.Shutdown(SocketShutdown.Send)</code> seemed to do the trick. I had wondered about this myself, but didn't really investigate it.</p> <p>What I don't understand is why calling this method has the effect it does. Doing some decompilation, that <code>Shutdown</code> method basically calls the <code>shutdown</code> method in the underlying WinSock library (ws2_32.dll) via pinvoke, does some error handling, then sets the socket to be disconnected. In the absence of any other information, this suggests that the 2 minute problem is created in that WinSock call.</p> <p>I tried to diagnose this by <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/bb892100(v=vs.85).aspx" rel="nofollow noreferrer">enabling WinSock logging</a> in the Event Viewer, but there didn't seem to be anything obvious that would point to why this was happening.</p> <p>Doing some more research down at the WinSock level turned up these questions:</p> <p><a href="https://stackoverflow.com/questions/9846165/winsock-recv-not-working-after-shutdown">Winsock recv not working after shutdown</a></p> <p><a href="https://stackoverflow.com/questions/3322538/multipe-sends-and-recvs-using-winsock2?rq=1">Multipe Send()&#39;s and Recv()&#39;s using Winsock2</a></p> <p><a href="https://stackoverflow.com/questions/13150910/why-http-server-close-the-connection-when-client-close-only-the-send-half-of-the?lq=1">Why HTTP server close the connection when client close only the send half of the connection?</a></p> <p><a href="https://stackoverflow.com/questions/4346120/why-does-net-socket-disconnect-take-two-minutes">Why does .Net Socket.Disconnect take two minutes?</a></p> <p>The common theme seems to be that <code>socket.Shutdown(SocketShutdown.Send)</code> isn't such a good idea if you intend on using the socket afterward for receiving. The fact that this method sets the <code>socket.Connected</code> property to false could be quite telling.</p> <p>The last link in the above list seemed rather close to the mark with the 2 minute situation, though the OP refers to registry settings but does not say what they are.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload