算法实现语言:C++
平台:win/linux
演示程序:https://webboy.lanzoul.com/i68wg5c 密码:udx
1,带宽。
对带宽的评估,预测。
l 在检测最大发送窗口的时候,是参照RENO算法,丢包检测.但是在之个过程中,UDX还检测了ACK的回复率,当出现ACK回复频率发生变化(变化率K > 0.35)时表明现在网络出现了波动,可以预测已经达到拥塞临界,这有点象VEGAS一样,可以提前预测出现拥塞,这时UDX调整慢启动阀值,提前进入拥塞避免阶段.
2,快速重传
UDX的ACK设计,其实就是SACK协议,但是实现手法是不同于SACK,sack是首尾序号对,而UDX是一个起始序号,及后面的相对序号组成,这样可以容纳更多的ACK.当发送方收到任何一个ACK时就可以准确的确定哪个包已经丢掉了,这时可以马上重传,而不需要等到超时后再重传,从而提高了实时性及间接的提高了吞吐量。
3,AIDM上有何改进
慢启动阶段和TCP类是W += 1,拥塞避免阶段是W += 1/W;
UDX在窗口管理上,也采用了不同的设计方法。其中引入了一个饱和状态,也就是最佳状态。而实际发送速度是这个最佳状态时的1.25倍发送速度。这样可以保证较高的竟争性。
UDX中,度量的单位是当前流量,控制窗口的核心思想是,控制流量的增量。当增量趋近于实际流量的<= 5%波动时,认为,流量已经最大,这时进入饱和状态,当UDX进入饱和状态时,转入拥塞避免加速模式,窗口不增大反而会减小,达到一个动态平横,使发送速度,始终稳定在一个水平上。
4,算法上有何优化
主要优化在于重传策略,及超时时间计算
重传策略上不同与其他算法,主要是
超时重传是由ACK驱动,而不是仅依靠定时器,这样可以更快的重传数据,增加实时性。
由于UDP的特性,目前 UDX是采用1.5倍计算的超时时间。超时时间为RTT + 4*|dRTT|
如果按传统的TCP的指数退避算法计算超时时间,在丢包和大延迟的网络,性能会急剧下降。
UDX主要重传发生在ACK到来时,由于收到ACK,说明网络正常,这时重发数据,比盲目依靠定时器重传可靠的多。UDX定时器只会每次发一个重发包,当网络恢复时,就会重新依靠ACK把重发包快速发出去。
5,针对wifi调整了什么参数
在无线3G领域,UDX没有做过多的优化,无线网络主要特性和有线网络还是比较明显。其特点是,波动大,流量不稳定,丢包率不固定,完全受环境的信号影响。
从这个特性上来看,UDX的若干改进还是比较适合这种环境,较其他算法,更有抗丢包和干扰。比如,ACK设计及快速重传等。
6,在多媒体传输上的优势
Udx主要体现在其实时性,特别适合传送视频,网络越复杂,环境 越是恶劣,越是适合UDX。对于音频,UDX适合在低延迟,低丢包率的网络(RTT小于150MS,丢包小于5%)。因为是可靠数据传播 ,相对于RTP这类实时协议音质要好很多。但实时性略差,或人感觉不出来,在丢包环境,只要延迟小于100ms,语音较RTP有较大提高,实时性也感觉不出来。
7.UDX接口。
提供了流式接口,包接口。
处理粘包问题,使用户只处理业务包,可以发送较大的业务包。接收方,收到的也只是业务包。
提拱P2P,接口及中转接口
8.参数设置
1.UDX全局设置
包括最小传输单元MSS
内部时钟
最小ACK回复间隔
最小超时
最大超时
多少个包应答一次
及最小初使窗口
2.UDX单个连接设置
连接超时
心跳包间隔
是否属于固定流量发送
流量估算由包个数转变为字节,使控制更加精确。
支持碎包。
支持多IP,在多网卡上转发,效率提高。
联接断开:
UDX采用是瘦断开,或叫不安全断开,向远端发送四次断开包,本地立即断开。
见以下附部分源码:
协议帧格式:
#ifdef WIN32
#pragma pack( push, 1 )
#define PACKED
#else
#define PACKED __attribute__((packed, aligned(1)))
#endifstruct _UdpHead //7
{
UDP_SHORT sendtime;
UDP_LONG SegIndex;
UDP_BYTE brto:1;
UDP_BYTE bnosacks:1;
UDP_BYTE type:4;
UDP_BYTE cid:2;
}PACKED;struct UdpHead //10 BYTE
{
UDP_BYTE bP2p:1;
UDP_BYTE bMquery:1;
UDP_BYTE bMregister:1;
UDP_BYTE bMTrans:1;
UDP_BYTE noused:4;
UDP_SHORT sum;//2
_UdpHead head;//7
}PACKED;
struct UdpProxyHead
{
UdpHead head;//10
INT64 des;//8
}PACKED;
struct UdpHeadAck : public UdpHead//ACK 11
{
UDP_BYTE ackcounts;
UDP_BYTE acks[1];
}PACKED;struct UdxHeadConnect : public UdpHead
{
SOCKADDR wanaddr;
UDP_SHORT maxwndsize;
UDP_SHORT servertime;
UDP_BYTE bAccept : 1;
UDP_BYTE state:7;
UDP_LONG datalen;
UDP_BYTE data[1];
}PACKED;struct PACKHEAD
{
UDP_SHORT btrans:1;
UDP_SHORT cmd:15;
UDP_LONG translen;
}PACKED;
struct TRANSPACKHEAD : public PACKHEAD
{
UDP_BYTE buffcount;
UDP_SHORT bufflen[1];
}PACKED;struct FileCmdBase
{
UDP_SHORT a,b,c;
UDP_LONG type;
UDP_LONG cmdlen;
BYTE data[1];
}PACKED;核心拥塞控制部分代码:部分主要控制变量
double m_uncheckdatasize;//发送出去,还没有被确认的包
double m_sendwinsize;//拥塞窗口
double m_sstresh;//慢启动伐值
double m_lasterWnd;//最大流量时的,窗口
double m_LastMaxFlow;//最大理论流量
double m_deltFlow;//理论流量波动值
double m_lastMaxWnd;//最大发送窗口
double m_AvageFlow;//平均流量
double m_expectwnd;//预期理论窗口
double m_lostrate;UDP_LONG m_currenttimerbyts;//一个周期内收到的数量
UDP_LONG m_WeekFlowTime;//流量下降时间
UDP_LONG m_cntStatble;//平稳周期计数
UDP_LONG m_LastAckArrivedTime;//最后一次ack到来时间,用来确定重发ACK的周期int m_cfgwndsize;//约定最大窗口
double m_ackcheckdatatrtt;//控制一个RTT周期增长1.
BOOL m_bQuickRecover;//快速恢复算法控制算法
// WindowControl.cpp: implementation of the CWindowControl class.
//
//////////////////////////////////////////////////////////////////////#include “WindowControl.h”
#include “UdxSocket.h”
#include “udxfunction.h”//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////CWindowControl::CWindowControl()
{
m_pUdx = NULL;
Reset();
}CWindowControl::~CWindowControl()
{}
void CWindowControl::OnPackArrived( DWORD datalen )
{
m_LastAckArrivedTime = GetTimer()->GetTickCount();//最后一次,数据到达时间
m_acktimewatcher.OnAck();
m_ackcheckdatatrtt += datalen;if(datalen == 0)
return;m_uncheckdatasize -= datalen;
m_currenttimerbyts += datalen;m_bew.OnAck(datalen);
IncreaseWndSize(TRUE,FALSE,datalen);
}void CWindowControl::OnPackTimeOutSend( DWORD datalen )
{
if(datalen == 0)
return;
IncreaseWndSize(FALSE,TRUE,datalen);
}void CWindowControl::OnPackQickReSend( DWORD datalen )
{
if(datalen == 0)
return;
IncreaseWndSize(FALSE,FALSE,datalen);}
void CWindowControl::OnSendNewData( DWORD datalen )
{
m_uncheckdatasize += datalen;
}BOOL CWindowControl::IsNetWorkHungry()
{
return m_uncheckdatasize < m_sendwinsize;
}void CWindowControl::SetCfgWnd( int wnd )
{
m_cfgwndsize = wnd;
}int CWindowControl::IsOverLoadWnd()
{
assert(m_pUdx);
double currentRtt = m_pUdx->GetRtt()->GetRTT();
double minrtt = m_pUdx->GetRtt()->GetMinTTL();double act = m_sendwinsize / (currentRtt / 1000);
double expect = m_sendwinsize / (minrtt / 1000);double DIFF = expect – act;
double a = (0.35f* GetUdxGlobalCfg()->mss) / (minrtt / 1000);
double lastflow = m_lasterWnd / (currentRtt / 1000);
double deltFlow = m_LastMaxFlow – act;
double be = m_bew.GetBew() * 1000;
double be2 = m_reb.GetBew() * 1000;int deltrtt = 1;
float krtt = currentRtt / __max(10,minrtt);
if(krtt > 2.5f && minrtt > 10)//decrease with rtt
{
deltrtt = __max(krtt*krtt*2,20);
}double expectwnd = be/*(be + be2) * 0.5f*/ * (__max(UDX_MIN_LOCALNETWORK_RTT,(currentRtt – deltrtt)) / 1000);
if(expectwnd >= GetUdxGlobalCfg()->mss*m_cfgwndsize)
{
expectwnd = GetUdxGlobalCfg()->mss*m_cfgwndsize;
}BOOL bOverBew = m_bew.IsOverLoad();
m_expectwnd = m_expectwnd*0.95f + expectwnd*0.05f;
m_AvageFlow = 0.85f* m_AvageFlow + 0.15f*act;
m_deltFlow = 0.75f* m_deltFlow + 0.25f*deltFlow;if(m_LastMaxFlow < act)
{
m_LastMaxFlow = m_LastMaxFlow*0.95f + 0.05f*act;if(bOverBew)
{
if(currentRtt > minrtt * 1.5f)
m_lasterWnd = m_lasterWnd*0.7f + 0.3f*(__min(m_expectwnd,m_sendwinsize));
else
{
if(currentRtt < minrtt * 3.5f)
m_lasterWnd = m_lasterWnd*0.7f + 0.3f*m_sendwinsize;
}
}
else
{
if(currentRtt < minrtt * 5)
m_lasterWnd = m_lasterWnd*0.7f + 0.3f*m_sendwinsize;
}
if(m_lasterWnd > m_expectwnd * 2)
m_lasterWnd = m_expectwnd * 2;
m_lasterWnd = __max(m_lasterWnd,m_expectwnd / 2);
}double diff = m_LastMaxFlow * 0.35f;
double maxdiff = __max(a,diff);if(m_deltFlow > maxdiff)
{
if(GetTimer()->GetTickCount() – m_WeekFlowTime > m_pUdx->GetRtt()->GetTimeOutRto())
{
ATLTRACE(“sss: %0.2f-%0.2f-%0.2f\n”,m_lasterWnd,m_sendwinsize,m_lastMaxWnd);
m_LastMaxFlow *= 0.95f;
m_WeekFlowTime = GetTimer()->GetTickCount();
}
}else
{
m_WeekFlowTime = GetTimer()->GetTickCount();
}if(DIFF < a)
{
return 0;
}
if(m_acktimewatcher.WaveLargeThan(1) || DIFF > 10*a)//回包波动率
{
if(m_sstresh > 2 * m_sendwinsize)
{
m_sstresh = m_sendwinsize;
}
}
if(m_sendwinsize <= m_expectwnd)
return 0;float kscan1 = 1.2f;
float kscan2 = 1.15f;if(minrtt > 10)
{
kscan1 += 0.5f;
kscan2 += 0.5f;
}float k = m_sendwinsize / m_lasterWnd;//竟争率
if(bOverBew && k > kscan1)
{
ATLTRACE(“TTL OVER LOAD1 %.02f,%.02f,%.02f\n”,k,m_sendwinsize,m_lasterWnd);
return 1;
}
if(m_reb.IsOverLoad() && k > kscan2)
{
ATLTRACE(“TTL OVER LOAD2 %.02f,%.02f,%.02f\n”,k,m_sendwinsize,m_lasterWnd);
return 2;
}
float k2 = (m_sendwinsize * m_lostrate) / m_expectwnd;
if(k2 > kscan1)
{
ATLTRACE(“TTL OVER LOAD3 %.02f,%.02f,%.02f\n”,k,m_sendwinsize,m_lasterWnd);
return 1;
}if(k2>1 && currentRtt > 2000)
{
ATLTRACE(“TTL OVER LOAD4 %.02f,%.02f,%.02f\n”,k,m_sendwinsize,m_lasterWnd);
return 1;
}return 0;
}void CWindowControl::Reset()
{
if(m_pUdx)
m_cfgwndsize = m_pUdx->GetUdxCfg()->wndmaxsize;//约定最大窗口
else
m_cfgwndsize = 0;m_uncheckdatasize = 0;//发送出去,还没有被确认的包
m_sendwinsize = MIN_SENDWINDOWSIZE;//拥塞窗口
m_sstresh = m_cfgwndsize*GetUdxGlobalCfg()->mss;
m_lasterWnd = MAX_SENDWINDOWSIZE;//最大流量时的,窗口
m_LastMaxFlow = MIN_SENDWINDOWSIZE;//最大理论流量
m_deltFlow = 0;//理论流量波动值
m_lastMaxWnd = 0;//最大发送窗口
m_AvageFlow = MIN_SENDWINDOWSIZE;//平均流量
m_expectwnd = MIN_SENDWINDOWSIZE;//预期理论窗口m_bQuickRecover = FALSE;
m_WeekFlowTime = GetTimer()->GetTickCount();//流量下降时间
m_cntStatble = 0;//平稳周期计数
m_LastAckArrivedTime = GetTimer()->GetTickCount();//最后一次,数据到达时间
m_ackcheckdatatrtt = 0;
m_lostrate = 0;m_LastSendToalCount = 0;
m_LastReSendCount = 0;m_currenttimerbyts = 0;
m_acktimewatcher.Reset();
m_bew.Reset();
m_reb.Reset();
m_acktimewatcher.Reset();
}
void CWindowControl::IncreaseWndSize(BOOL bIncrease,BOOL bTimeOut,DWORD dwData)
{
Udx_IncreaseWndSize(bIncrease,bTimeOut,dwData);if(m_sstresh <= MIN_SSTHRESH || m_sendwinsize <= MIN_SENDWINDOWSIZE)
{
m_sstresh = m_cfgwndsize*GetUdxGlobalCfg()->mss;
m_sendwinsize = MIN_SENDWINDOWSIZE;
m_LastMaxFlow = MIN_SENDWINDOWSIZE;
m_lastMaxWnd = MIN_SENDWINDOWSIZE;
m_AvageFlow = MIN_SENDWINDOWSIZE;
m_deltFlow = 0;
m_lostrate = 0;
m_acktimewatcher.Reset();
m_bew.Reset();
m_reb.Reset();
}if(m_sendwinsize > m_cfgwndsize * GetUdxGlobalCfg()->mss)
{
m_sendwinsize = m_cfgwndsize * GetUdxGlobalCfg()->mss;
}m_cntStatble += bIncrease;
if(m_pUdx->GetUdxCfg()->fixedwnd)
{
m_sendwinsize = m_pUdx->GetUdxCfg()->fixedwnd * GetUdxGlobalCfg()->mss;
}
assert(m_cfgwndsize >= 8);
assert(m_sendwinsize >= MIN_SENDWINDOWSIZE);
}
void CWindowControl::Udx_IncreaseWndSize( BOOL bIncrease,BOOL bTimeOut,DWORD dwData )
{……太长省略……
附件源码列表: