使用 C# .Net 4.5 的高效且可扩展的连接 TCP Windows 服务

Posted

技术标签:

【中文标题】使用 C# .Net 4.5 的高效且可扩展的连接 TCP Windows 服务【英文标题】:Efficient & Scalable connected TCP Windows Service using C# .Net 4.5 【发布时间】:2017-05-06 12:55:27 【问题描述】:

要求: 需要一个基于 Windows 服务的 C# .NET 4.5 始终(至少长)连接的 TCP 服务器架构,具有垂直和水平扩展,并且每个服务器可以处理最大可能的连接。客户端可以是任何 IoT(物联网)。

我知道端口的限制,但仍然想知道为什么在这个技术时代有这些限制(我们总是有限制,但为什么仍然是旧的?!)。临时 tcp/http 连接也可以很好地扩展,但在这里不是必需的。

设计:

每个服务器一个线程用于异步接受新连接(服务器的生命周期)。 代码:rawTcpClient = await tcpListener.AcceptTcpClientAsync();

每个客户端连接(循环)一个线程来保持客户端连接? (见下面我的问题)

用于执行客户端操作的任务(短期、间歇性 操作)

我关于优化的问题(如果可能?): 我如何优化/管理以将所有客户端连接保存在一组线程/线程池中,而不是每个连接一个线程,因为这是可能持续很长时间的客户端生命周期? 例如:每台服务器仅分配 50 个基于线程的任务来保持连接的客户端,这样它们就不会在等待客户端数据时断开连接?

【问题讨论】:

也许这仍然是 WCF 的一个用例.. WCF 正是这样做的。 而且你可能不应该使用那么多线程 【参考方案1】:

高效且可扩展

您需要决定的第一件事是您希望如何高效。如果效率是您的首要任务,那么套接字 API 可能会变得非常复杂。然而,效率几乎从来没有是重中之重,尽管很多人认为确实如此。问题是复杂性会随着效率/可扩展性成倍增加,如果你只是最大化效率/可扩展性,你最终会得到一个几乎无法维护的系统。因此,您需要决定在该比例尺上画线的位置。

特别是如果您有水平扩展,您可能不需要使用极高效的套接字 API。

我知道端口的限制,但仍然想知道为什么在这个技术时代有这些限制(我们总是有限制,但为什么还是旧的限制?!)。

兼容性。特别是端口由 16 位值表示。改变这种情况的唯一方法是,如果一个新标准出来了,一切都升级了。 NIC、网关、ISP 和 IoT 设备。这是一个高要求,可能永远不会发生。

每个服务器一个线程用于异步接受新连接(服务器的生命周期)。

没关系。如果你有大量的连接周转,你也可以有多个接受线程。只需保持高积压(在 Windows Server 操作系统上默认应该高)。

每个客户端连接(循环)一个线程来保持客户端连接?

呃,没有。

您肯定会想要使用异步 I/O。

您应该在所有连接的客户端上进行连续(异步)读取,然后根据需要进行(异步)写入。此外,如果协议允许,您应该定期向每个连接的客户端写入心跳消息;否则,您需要为每个客户端设置一个计时器来断开连接。根据写入的性质,您可能需要为每个客户端设置一个待处理的写入队列。

用于执行客户端操作的任务(短期、间歇性 操作)

如果您使用异步任务,那么您的所有实际代码都将在任何可用的线程池线程上运行。根本不需要专门的任务。

您可能会发现我的TCP/IP .NET Sockets FAQ 很有帮助。

【讨论】:

我尝试了异步读取(异步 I/O),但发现每个客户端始终需要一个线程来持续读取客户端并保持连接。相同的线程 (ID) 继续进行后续读取,并且未被释放。我浏览了您的优秀博客,但找不到有关在单线程或有限池中管理多个客户端连接的示例或更多详细信息。 @Guru_07:异步 I/O 仅使用 in between await 点的线程。如果您没有使用SynchronizationContextTaskScheduler,那么它将使用线程池线程。完全有可能使用相同的线程池线程来恢复该方法,尤其是在低压力测试中。这没有什么问题;这实际上是一种优化(线程池使用work-stealing per-thread queues to maximize per-processor caches)。

以上是关于使用 C# .Net 4.5 的高效且可扩展的连接 TCP Windows 服务的主要内容,如果未能解决你的问题,请参考以下文章

在 C# .NET 4.5 中使用 SAML 2.0

.NET 4.5 和 C# 中带有 HttpClient 的 HTTP HEAD 请求

如何在 C# (.NET 4.5) 中为 HttpClient.GetAsync(URI) 创建回调?

C# sapnco支持.net 4.5了,真是个意外的发现

如何使用 Oracle 和 SQL Server 将 .NET 4.5 C# Entity Framework 6 中的列映射为大写?

C# .NET 4.5 将多个文件添加到压缩包中