关于提高UDP发送效率的方法

开发问题 专栏收录该内容
41 篇文章 0 订阅

UDP的发送效率和什么因素有关呢?

直观认为,UDP的切包长越大,应该发送效率越高(最长为65536)。但是根据实际测试和在网上查到的资料的结果,包长度为1024为发送效率最高。


这种结果让人感到疑惑,为什么是1024这种奇怪的值呢?为什么不是MTU(最小发送单元)的长度(即1500-28)呢?

后来调查发现,Windows的网络底层,默认UDP分片长度为1024时,走的是快速通道模式,具体怎样的快速通道?没有再继续深入研究。

通过修改下面的注册表可以加大1024.

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AFD\Parameters\FastSendDatagramThreshold

并且需要修改网卡注册表的MTU与上面的值一致,具体注册表项如下所示:

HKEY_LOCAL_MACHINE\\SYSTEM\CurrentControlSet\services\Tcpip\Parameters\Interfaces\MTU

修改以上注册表值的示例代码:

// 修改本地UDP包发送长度并根据网络MTU确定实际UDP发送的包长度
// <span style="font-family: Arial, Helvetica, sans-serif;">lenPacket【out】:包长度,</span><span style="font-family: Arial, Helvetica, sans-serif;">bIsToRestartComputer【out】:是否重启计算机(当修改了注册表,则需要重启有效)</span>
<pre name="code" class="cpp"><span style="font-family:Arial, Helvetica, sans-serif;">// 返回:TRUE(成功),FALSE(失败)</span>

 
BOOL SetMaxEfficencyUDPPacketLength(INT &lenPacket, BOOL &bIsToRestartComputer)
{
	// 初始化
	lenPacket = MAX_SUPER_DISPLAY_UDP_LENGTH;
	// 设置【HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AFD\Parameters】
	// 添加FastSendDatagramThreshold=1500
	if (!CUtil::IsKeyExist(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\AFD\\Parameters"),
		_T("FastSendDatagramThreshold")))
	{
		// 如果写入失败,则按照发送
		if (!CUtil::WriteKey(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\AFD\\Parameters"),
			_T("FastSendDatagramThreshold"), MTU_DEFAULT))
		{
			lenPacket = NOT_SET_FAST_SEND_DATAGRAME_UDP_LENGTH;
			return FALSE;
		}
		bIsToRestartComputer = TRUE;
	}
	// 校验值
	else
	{
		INT iValue = 0;
		// 获取键值
		if (CUtil::ReadKey(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\AFD\\Parameters"),
			_T("FastSendDatagramThreshold"), iValue))
		{
			// 如果键值不是MTU默认值,则修改
			if (iValue != MTU_DEFAULT)
			{
				// 如果写入失败,则按照发送
				if (!CUtil::WriteKey(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\AFD\\Parameters"),
					_T("FastSendDatagramThreshold"), MTU_DEFAULT))
				{
					lenPacket = NOT_SET_FAST_SEND_DATAGRAME_UDP_LENGTH;
					return FALSE;
				}
				bIsToRestartComputer = TRUE;
			}
		}
	}

	// 设置【HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Tcpip\Parameters\Interfaces】
	// 修改MTU=1500
	// 如果不存在,则返回
	HKEY hMainKey = NULL;
	LONG lRetCode = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,_T("SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces"),0,KEY_READ,&hMainKey);
	if(lRetCode != ERROR_SUCCESS)
	{
		return TRUE;
	}
	// 遍历所有网口,修改MTU
	DWORD dwIndex = 0;
	TCHAR swzSubKey[MAX_PATH] = _T("");
	DWORD dwNameLen = MAX_PATH;
	while(ERROR_SUCCESS == ::RegEnumKeyEx(hMainKey, dwIndex, swzSubKey, &dwNameLen, NULL, NULL, NULL, NULL))
	{
		// 构造子键全路径
		CString strFullSubKey = _T("SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces\\");
		strFullSubKey += swzSubKey;
		// 修改MTU
		if (CUtil::IsKeyExist(HKEY_LOCAL_MACHINE, strFullSubKey, _T("MTU")))
		{
			INT iValue = 0;
			// 获取键值
			if (CUtil::ReadKey(HKEY_LOCAL_MACHINE, strFullSubKey, _T("MTU"), iValue))
			{
				// 如果键值不是MTU默认值,则修改
				if (iValue != MTU_DEFAULT)
				{
					// 如果写入失败,则按照发送
					if (!CUtil::WriteKey(HKEY_LOCAL_MACHINE, strFullSubKey, _T("MTU"), MTU_DEFAULT))
					{
						lenPacket = NOT_SET_FAST_SEND_DATAGRAME_UDP_LENGTH;
						return FALSE;
					}
					bIsToRestartComputer = TRUE;
				}
			}
		}
		// 重置缓存
		memset(swzSubKey, 0, sizeof(swzSubKey));
		dwNameLen = MAX_PATH;
		// 下一个子项
		dwIndex ++;
	}
	::RegCloseKey(hMainKey);

	return TRUE;
}

但是需要注意的是,修改此值需要确保小于或者等于整个网络路径的MTU,怎样检查整个网络的MTU呢?可以通过执行下面指令获取:

ping -f -n 1 -l 1472 192.168.0.2

其中,1472为发送的包长度,如果执行结果为0,表示能够发送;可以继续提高1472,否则降低;直至获取最大值。

具体代码如下所示:

// 获取网络MTU
// ulDestIP【in】:目标IP
// 返回:MTU
UINT GetLanMTU(ULONG ulDestIP)
{
	// 初始化
	UINT lenPacket = NOT_SET_FAST_SEND_DATAGRAME_UDP_LENGTH;
	// 指令缓存
	CHAR szCmdBuf[MIDDLE_BUF_LENGTH];
	memset(szCmdBuf, 0, sizeof(szCmdBuf));
	// 构造指令
	sprintf_s(szCmdBuf, MIDDLE_BUF_LENGTH, "ping -f -n 1 -l 1472 %s",
		inet_ntoa(*(struct in_addr *)&ulDestIP));
	// 执行指令
	INT iRet = system(szCmdBuf);
	// 如果MTU是
	if (iRet == 0)
	{

		lenPacket = MAX_SUPER_DISPLAY_UDP_LENGTH;
	}else
	{
		CUtil::OutputConsoleLogString("LAN's MTU isn't 1500");
	}

	return lenPacket;
}


  • 3
    点赞
  • 0
    评论
  • 11
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值