Share via


C# advanced socket server - 100% CPU usage after some time

Question

Thursday, November 5, 2009 9:41 PM

Hello,

I've created a quite advanced server using C# which servers as a server for a multiplayer silverlight game. It features async sockets (modified code from MSDN example), has connection to a MSSQL database and is sending/receiving XML data.

The problem is, that after some time and some clients going offline/online, creating/joining games etc. it's CPU usage raises to 100% (even if there aren't any clients connected at that time).

Do you have any ideas what could be wrong (you know, some common issues that not-so-skilled programmers encounter)? Could it be that some objects aren't getting disposed properly (it would be more logical that RAM usage would be high in that case, wouldn't it?)?

Thank you for your help.

Regards,
N37-L0RD

All replies (6)

Friday, November 6, 2009 1:37 PM âś…Answered

A correctly-written socket server isn't subject to the client's implementation quirks. It must properly respond if the client gracefully closes the connection, abruptly closes the connection, or just decides to stop sending data on the connection.

Any socket connection may return 0 bytes from EndReceive (indicating graceful closure), throw an exception from EndReceive (indicating an abrupt closure), or the EndReceive may not complete. This last case may indicate a half-open connection (see http://nitoprograms.blogspot.com/2009/05/detection-of-half-open-dropped.html). Half-open connections must be dealt with one of two ways, both of which require an activity timer: either send a "keepalive" message across the connection if nothing has been read for a period of time, or just close the connection if nothing has been read for a period of time. Every long-running server must have an activity timer. (And note that the Socket.Connected property is entirely useless - it will not detect half-open connections; the timer has to either send data or close the socket).

Back to the three options for socket receiving: they'll either return 0, throw an exception, or not complete. Note that 100% CPU usage is not one of those options. The 100% CPU usage does indicate a bug in the server. Since EndReceive isn't throwing or returning 0, then it must not be completing (so you'll need an activity timer to detect this), but this will not fix the 100% CPU. That must be a separate bug.

       -Steve

Programming blog: http://nitoprograms.blogspot.com/
  Including my TCP/IP .NET Sockets FAQ

Microsoft Certified Professional Developer


Thursday, November 5, 2009 9:57 PM

Open task manager. Go to view -> select columns and make sure handles, threads, and GDI objects (GDI probably doesn't matter for a server) are checked. See if any of those keep increasing.


Thursday, November 5, 2009 10:06 PM

Handles are around 370, threads around 15 and GDI objects are 19. Handles and threads do increase when a client connects, but they increase for 1-5 and they go back to average count after a few seconds of server being idle.


Friday, November 6, 2009 1:37 AM | 2 votes

The MSDN socket examples are very poor quality. Most (all?) of them do have a bug where they will hit 100% CPU usage if a client socket gracefully closes before sending an "end of transmission" message.

Ensure that your code will respond properly to a Receive/EndReceive that returns 0 bytes (the response should be to close the socket and stop reading).

      -SteveProgramming blog: http://nitoprograms.blogspot.com/
  Including my TCP/IP .NET Sockets FAQ

Microsoft Certified Professional Developer


Friday, November 6, 2009 12:44 PM

I thought I've taken care of this problem, because I do remove sockets when EndReceive fails, which always happens when SILVERLIGHT clients close unexpectedly. But I also have Adobe Flash client which somehow doesn't do anything with the connection after it closes unexpectedly and I can't detect that.

I partialy solved the problem by making a silvelight "connection helper" which is called via JavaScript and makes paralalel connection with silverlight and after page refreshes or is navigated away, server checks the closed helper's ID and also removes the flash socket.

However, this apparently has a flaw - it doesn't work if flash closes BEFORE it calls silverlight helper. (I intentionaly did that and my CPU went to 100%)

**Is there any other way of detecting "bad" sockets (EndReceive doesn't throw an error and no 0 byte receives happen)?
**

I could do a timer that checks sockets every few seconds, but that is not really what i want.

Thanks


Friday, November 6, 2009 2:05 PM

Ok, I'll make a timer which sends costum "keepalive" messages to check for bad sockets.

Thanks