如何最大限度地减少 TCP 服务器应用程序中使用的线程数?
我正在寻找人们在实现为客户端 TCP(或 UDP)请求提供服务的服务器应用程序时使用的任何策略:设计模式、实现技术、最佳实践等。
出于此问题的目的,我们假设请求相对较长寿命(几分钟)并且流量对时间敏感,因此响应消息时不可接受任何延迟。 此外,我们既服务来自客户端的请求,又建立与其他服务器的连接。
我的平台是 .NET,但由于无论平台如何,底层技术都是相同的,因此我有兴趣查看任何语言的答案。
I am looking for any strategies people use when implementing server applications that service client TCP (or UDP) requests: design patterns, implementation techniques, best practices, etc.
Let's assume for the purposes of this question that the requests are relatively long-lived (several minutes) and that the traffic is time sensitive, so no delays are acceptable in responding to messages. Also, we are both servicing requests from clients and making our own connections to other servers.
My platform is .NET, but since the underlying technology is the same regardless of platform, I'm interested to see answers for any language.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您好,
我首先看一下您想要用于线程框架的隐喻。
也许是“领导跟随者”,其中线程正在侦听传入请求,当新请求进入时,它会执行工作,并且池中的下一个线程开始侦听传入请求。
或者线程池,其中同一线程始终侦听传入请求,然后将请求传递给线程池中的下一个可用线程。
您可能想访问 Ace 的 Reactor 部分组件以获得一些想法。
HTH。
干杯,
抢
G'day,
I'd start by looking at the metaphor you want to use for your thread framework.
Maybe "leader follower" where a thread is listening for incoming requests and when a new request comes in it does the work and the next thread in the pool starts listening for incoming requests.
Or thread pool where the same thread is always listening for incoming requests and then passing the requests over to the next available thread in the thread pool.
You might like to visit the Reactor section of the Ace Components to get some ideas.
HTH.
cheers,
Rob
更复杂的方法是使用 IO 完成端口。 (视窗)
通过 IO 完成端口,您可以将轮询留给操作系统来管理,这使得它可以通过 NIC 驱动程序支持使用非常高水平的优化。
基本上,您有一个由操作系统管理的网络操作队列,并提供一个在操作完成时调用的回调函数。 有点像(硬盘)DMA,但用于网络。
Len Holgate 几年前在 Codeproject 上写了一篇关于 IO 完成端口的精彩系列文章:
http://www.codeproject.com/KB/IP/jbsocketserver2.aspx
以及
我找到了一篇关于 .net 的 IO 完成端口的文章(虽然还没有读过)
http://www.codeproject.com/KB/cs/managementiocp.aspx
我还想说,与尝试编写可扩展的替代方案相比,使用完成端口很容易。 问题是它们仅适用于 NT(2000、XP、Vista)
A more sophosticated aproach would be to use IO Completion ports. (Windows)
With IO Completion ports you leave to the operating system to manage polling, which lets it potentially use very high level of optimization with NIC driver support.
Basically, you have a queue of network operations which is OS managed, and provide a callback function which is called when the operation completes. A bit like (Hard-drive) DMA but for network.
Len Holgate wrote an eccelent series on IO completion ports a few years ago on Codeproject:
http://www.codeproject.com/KB/IP/jbsocketserver2.aspx
And
I found an article on IO completion ports for .net (haven't read it though)
http://www.codeproject.com/KB/cs/managediocp.aspx
I would also say that it is easy to use completion ports compared to try and write a scaleable alternative. The problem is that they are only available on NT (2000, XP, Vista)
如果您直接使用 C++ 和 Win32,那么我建议您阅读有关重叠 I/O 和 I/O 完成端口的信息。 我有一个免费的 C++、IOCP、客户端/服务器框架,具有完整的源代码,请参阅 此处了解更多详情。
由于您使用的是 .Net,因此您应该考虑使用异步套接字方法,这样您就不需要为每个连接都有一个线程; 我的这篇博客文章中有几个链接可能是有用的起点:http://www.lenholgate.com/blog/2005/07/disappointing-net-sockets-article-in-msdn-magazine-this-month.html (一些最好的链接位于原始帖子的评论中!)
If you were using C++ and the Win32 directly then I'd suggest that you read up about overlapped I/O and I/O Completion ports. I have a free C++, IOCP, client/server framework with complete source code, see here for more details.
Since you're using .Net you should be looking at using the asynchronous socket methods so that you don't need have a thread for every connection; there are several links from this blog posting of mine that may be useful starting points: http://www.lenholgate.com/blog/2005/07/disappointing-net-sockets-article-in-msdn-magazine-this-month.html (some of the best links are in the comments to the original posting!)
现代方法是利用操作系统为您复用许多网络套接字,从而使您的应用程序只处理活动的流量连接。
每当您打开一个套接字时,它就会与一个选择器相关联。 您使用单个线程来轮询该选择器。 每当数据到达时,选择器都会指示套接字处于活动状态,您将该操作移交给子线程并继续轮询。
这样,每个并发操作只需要一个线程。 打开但空闲的套接字不会占用线程。
The modern approach is to make use of the operating system to multiplex many network sockets for you, freeing your application to only processing active connections with traffic.
Whenever you open a socket it's associated it with a selector. You use a single thread to poll that selector. Whenever data arrives, the selector will indicate the socket which is active, you hand off that operation to a child thread and continue polling.
This way you only need a thread for each concurrent operation. Sockets which are open but idle will not tie up a thread.