问题描述
我正在尝试提高基于 .NET 5 的网络代码的性能以提高吞吐量。我一直在使用标准的 .NET Sockets 实现 - 但是当涉及到大约 200Mbps(1kb 数据包)的吞吐量时,我遇到了一些困难。我已经尝试了异步模式的两种变体(Begin... 和 SendToAsync...)并使用使用同步操作的专用线程 - 但无法进一步提高性能。发送方和接收方的总体 cpu 负载低于 50% - 并且机器以 1Gbps 的速度连接。
我还尝试使用 Pcap.Net 甚至 Windows 数据包过滤器驱动程序 (http://ntkernel.com) 插入套接字层下方的 Ndis。
阅读表明,注册 I/O 可能是一个很好的方法,但在我的情况下,我需要使用 SocketType.Raw(因为我需要处理 GRE、SCTP 和除 UDP 和 TCP 之外的各种其他协议)。注册 I/O API 似乎不支持原始(IP 级)套接字(请参阅 https://docs.microsoft.com/en-us/windows/win32/api/mswsock/nc-mswsock-lpfn_riocreaterequestqueue)
分析器建议将时间花在 WSASendTo 中 - 并且 .NET Socket 类引入的额外开销很少。这表明即使直接使用 Winsock 从 C# 迁移到 C++ 也不太可能有太大帮助。我宁愿避开内核开发。
是否有类似于注册 I/O 的东西可以与原始套接字一起使用?注册 I/O 应该直接支持 UDP 而不是 IP,这似乎很奇怪。我如何解决这个瓶颈的任何其他想法? Winsock 是否存在与原始套接字(与 UDP 和 TCP 相对)相关的固有低效?
根据要求 - 添加了一个简单示例以尽快发送 1Kb 虚拟 GRE 数据包。这导致大约 270Mbps 的吞吐量和大约 30% 的 cpu 在所有内核上均匀分布。使用 localhost 时的性能大致相同 - 我认为这排除了网卡作为瓶颈的可能性。
using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.sockets;
namespace RawSender
{
class Program
{
private static readonly ConcurrentBag<socketasynceventargs> ArgsPool = new ConcurrentBag<socketasynceventargs>();
static void Main(string[] args)
{
var Destination = IPAddress.Parse(args[0]);
// Create pool of socketasynceventargs for the async operations
for (int Index=0;Index<10_000;Index++)
{
var Args = new socketasynceventargs();
Args.SetBuffer(new byte[1000]);
Args.Completed += OnComplete;
Args.RemoteEndPoint = new IPEndPoint(Destination,0);
ArgsPool.Add(Args);
}
// Send 1 million dummy 1kb packets using IP protocol 47 (GRE)
var Socket = new Socket(AddressFamily.InterNetwork,SocketType.Raw,(ProtocolType)47);
for(int Scan=0;Scan<1_000_000;Scan++)
{
if (!ArgsPool.TryTake(out socketasynceventargs Args)) throw new Exception("Args pool empty");
if (!Socket.SendToAsync(Args))
{
OnComplete(null,Args);
}
}
}
private static void OnComplete(object sender,socketasynceventargs e)
{
ArgsPool.Add(e);
}
}
}
解决方法
玩弄您的代码,似乎您受到发送的数据包开销数量的限制。使用您编写的代码,我获得了 246MB/s 的吞吐量,当我将缓冲区大小增加到 10000(即比您的大 10 倍)时,我获得了 2346MB/s(即再次大了 10 倍)。
就像任何其他类型的套接字编程一样,将您的套接字消息更好地组合在一起,并且如果您每秒发送数百万个这些消息,请不要说您不能。 >