zoukankan      html  css  js  c++  java
  • 关于提高UDP发送效率的方法

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

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


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

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

    通过改动以下的注冊表能够加大1024.

    HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesAFDParametersFastSendDatagramThreshold

    而且须要改动网卡注冊表的MTU与上面的值一致,详细注冊表项例如以下所看到的:

    HKEY_LOCAL_MACHINE\SYSTEMCurrentControlSetservicesTcpipParametersInterfacesMTU

    改动以上注冊表值的演示样例代码:

    // 改动本地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_MACHINESYSTEMCurrentControlSetServicesAFDParameters】
    	// 加入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_MACHINESYSTEMCurrentControlSetservicesTcpipParametersInterfaces】
    	// 改动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;
    }


  • 相关阅读:
    vue table 固定首列和首行
    手机号隐藏中间4位变成****
    微信小程序填坑之page[pages/XXX/XXX] not found.May be caused by
    table表格固定前几列,其余的滚动
    大文件切片功能
    js如何判断数字是否有小数
    获取当前时间前后6个月的时间数组
    为你的mail server增加SPF记录
    给hmailserver添加DKIM签名
    HttpWatch工具简介及使用技巧
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4390221.html
Copyright © 2011-2022 走看看