27

I'm tasked with designing a fairly simple TCP/IP server that must accept connections from multiple clients. It needs to be written in C#, and I'm using .NET 4.5. That said, I'm not sure what is the current "state of the art" for TCP/IP server/client scalability in .NET 4.5.

I did see this post: How to write a scalable Tcp/Ip based server. But that relates to .NET 2.0 and 3.5 and makes no mention of the async/await pattern.

I am capable of writing a server the "old way"... but I want to know what the "new way" is.

  • What is the best way to use the new Async methods on Socket, TcpClient or TcpListener to create a scalable server in C#?
  • Do the new Async methods leverage I/O Completion Ports?
  • Is rolling your own Socket listener more efficient, or are the TcpListener/TcpClient classes pretty good now?

EDIT: Additional questions.

Community
  • 1
  • 1
Ben Lesh
  • 107,825
  • 47
  • 247
  • 232
  • 3
    there is no C# 4.5 :) it's .net 4.5, C# 5 – Ravi Gadag Jan 31 '13 at 15:14
  • Sigh.. that's stupid. Thanks for correcting me. – Ben Lesh Jan 31 '13 at 15:16
  • Could have a look at http://signalr.net/ – Richard Jan 31 '13 at 15:18
  • What is your TCP/IP server going to be doing? Horses for courses and all that... – KingCronus Jan 31 '13 at 15:19
  • 2
    This might be useful - http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx – stuartd Jan 31 '13 at 15:20
  • It's going to be sending messages to and recieving messages from windows clients. – Ben Lesh Jan 31 '13 at 15:20
  • @StuartDunkeld, +1 for the interesting article, it shows some interesting async pattern basics and is a good read, but it doesn't really answer my question. – Ben Lesh Jan 31 '13 at 15:25
  • Personally I think using of async methods is not even a good idea for a big TCP/IP server. It is better to keep lot of parts in one or two (or even more) threads with non-blocking connections. You can check for new data and handle them and this is much faster, reliable and safer. That is what most of browsers and web servers do. – Soroush Falahati Jan 31 '13 at 15:29
  • 3
    @SoroushFalahati: Async using I/O completion ports shouldn't block threads. In fact, most of the Begin/AsyncResult type I/O methods in .NET 3.5 and higher leverage IOCP, so they shouldn't block any threads like async in .NET 2.0 did. – Ben Lesh Jan 31 '13 at 15:32
  • 3
    @SoroushFalahati: Actually, I'm pretty sure the vast majority of browsers and web servers use *asynchronous* methods. IOCP-based, specifically. – Stephen Cleary Jan 31 '13 at 15:37
  • @blesh & StephenCleary , Thanks for informing me about IOCP in new versions of .Net. But at other hand IOCP is almost same as using not blocking but with async like interface from what I learn from internet. Isnt it? – Soroush Falahati Jan 31 '13 at 17:23
  • 1
    Have you considered using a network library such as networkcomms.net? There is a good example of it in action here http://www.networkcomms.net/creating-a-wpf-chat-client-server-application/ – MarcF Feb 01 '13 at 12:40

1 Answers1

11

What is the best way to use the new Async methods on Socket, TcpClient or TcpListener to create a scalable server in C#?

There aren't any new async methods on Socket; the methods named *Async on Socket are a special set of APIs to reduce memory usage. TcpClient and TcpListener did get some new async methods.

If you want the best scalability, you're probably best using Stephen Toub's custom awaiters for Socket. If you want the easiest to code, you're probably better off using TcpClient and TcpListener.

Do the new Async methods leverage I/O Completion Ports?

Yes, just like most of the other asynchronous APIs in the BCL. AFAIK, the Stream class is the only one that may possibly not use the IOCP; all other *Begin/*End/*Async methods use the IOCP.

Is rolling your own Socket listener more efficient, or are the TcpListener/TcpClient classes pretty good now?

The classes are pretty good as they are. Stephen Toub has a blog post that is a bit more efficient in terms of memory use.

GMariakis
  • 544
  • 3
  • 7
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Not related to the question, what is IO Completion port? I am sorry, VB background makes me not come across this. Thanks. – shahkalpesh Jan 31 '13 at 15:49
  • @StaurtDunkeld linked that article above. I looked over it, and I guess I didn't notice it was an attempt to create a more efficient listener/client. I'm trying to understand what makes it more memory efficient. Is it that you don't need to instantiate a TcpClient and keep it around to manage the connection? – Ben Lesh Jan 31 '13 at 15:52
  • 1
    @shahkalpesh: [An efficient way to handle lots of asynchronous I/O](http://msdn.microsoft.com/en-us/library/aa365198%28v=VS.85%29.aspx). .NET currently uses one IOCP per app domain, tied in to the thread pool. – Stephen Cleary Jan 31 '13 at 15:54
  • 3
    @blesh: No; it's because it uses the `Socket` `*Async` methods. Normally, an asynchronous operation needs to allocate a structure per operation (`IAsyncResult`, analogous to `OVERLAPPED`). The `Socket` `*Async` methods use `SocketAsyncEventArgs`, which is kind of like a reusable `IAsyncResult`. So there's less allocation/deallocation, and less pressure on the GC. – Stephen Cleary Jan 31 '13 at 15:56
  • 1
    Thank you for the answer(s). I think what I'm going to do is use TcpListener/TcpClient and abstract them away so if I need to optimize later with Toub's method I can. – Ben Lesh Jan 31 '13 at 15:59
  • ... actually, screw it, I'll use Toub's method, it seems pretty straight forward, thanks again. – Ben Lesh Jan 31 '13 at 16:00
  • 1
    @StephenCleary And what's very relevant to servers, you have control over where in memory the `SocketAsyncEventArgs` are; just the cost of allocating and deallocating the buffers is non-trivial, but fairly easily manageable. The problem is that while you're doing any native operations on that buffer, it needs to be pinned, and cannot be moved by the GC. This can quickly balloon the memory used by the process as the heap cannot be properly compacted - we got ridiculous heap fragmentation in a day or two as a result (though of course, modern .NET is much better at that too). – Luaan Jan 16 '23 at 07:32