1.【opensips2.4源码分析】udp协议处理
2.基于UDP传输协议的源码实现分析之流量和拥塞控制
3.Windows下C语言多线程实现UDP通信程序recvfrom()函数出现10054错误:远程主机强迫关闭了一个现有的连接。
【opensips2.4源码分析】udp协议处理
在opensips 2.4的源码源码中,udp协议处理是源码通过内置的静态模块proto_udp实现的。这个模块主要集中在proto_udp.c文件中,源码通过结构体module_exports的源码cmds和params来配置,其中"udp_port"是源码c 字典源码唯一的可配置参数,默认值为。源码
关键的源码函数proto_udp_init负责初始化协议处理结构体struct proto_info,它负责设置udp的源码监听、发送和接收功能,源码这些底层操作在proto_udp.c文件中具体实现。源码在opensips主程序启动时,源码通过trans_load函数加载所有通信协议,源码其中会查找并调用proto_init函数,源码如proto_udp的源码jeasyui项目源码proto_init函数,用于初始化proto_info结构。
udp的监听逻辑根据配置文件进行,配置中的listen指令决定监听的端口。opensips使用struct socket_id结构体来抽象监听,这个结构在cfg.y的flex语法文件中生成,并在trans.c的add_listener函数中添加到全局的protos数组。在主程序启动的内核钩子源码最后阶段,会调用udp_proto模块的tran.init_listener函数来启动监听,但实际监听端口可能根据配置有所调整,如果没有相应的配置,该协议将被禁用。
基于UDP传输协议的实现分析之流量和拥塞控制
UDP的概念UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是0轴源码OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,IETF RFC 是UDP的正式规范。UDP在IP报文的协议号是。
流量控制
对于一个带宽1Gbps, RTT为ms的网络来说
BDP=1,,,*0.1/8=,,字节=K=M
传统TCP接收窗口大小=byte=K, 显然满足不了
udt使用包大小byte, 默认接口窗口大小为, 因此
接收窗口的大小为=*=,,字节=K=.7M
因此, 可以看到udt的默认设置已经足够.
Congestion Control(拥塞控制)
1. 两个重要的参数:
congestion window size and the inter-packet sending interval
2. 主要的接口
1) init: when the UDT socket is connected.
2) close: when the UDT socket is closed.
3) onACK: when ACK is received.
4) onLOSS: when NACK is received.
5) onTimeout: when timeout occurs.
6) onPktSent: when a data packet is sent.
7) onPktRecv: when a data packet is received.
3. udt的拥塞算法:
On ACK packet received:
1) If the current status is in the slow start phase, set the
congestion window size to the product of packet arrival rate and
(RTT + SYN). Slow Start ends. Stop.
2) Set the congestion window size (CWND) to: CWND = A * (RTT + SYN) +.
3) The number of sent packets to be increased in the next SYN period
(inc) is calculated as:
if (B = C)
inc = 1/PS;
else
inc = max(^(ceil(log((B-C)*PS*8))) * Beta/PS, 1/PS);
where B is the estimated link capacity and C is the current
sending speed. All are counted as packets per second. PS is the
fixed size of UDT packet counted in bytes. Beta is a constant
value of 0..
4) The SND period is updated as:
SND = (SND * SYN) / (SND * inc + SYN).
Java代码
复制代码
代码如下:
strong/strong1.Java代码
2.*/
3.publicvoidonACK(longackSeqno){
4.//increasewindowduringslowstart
5.if(slowStartPhase){
6.congestionWindowSize+=ackSeqno-lastAckSeqNumber;
7.lastAckSeqNumber=ackSeqno;
8.//butnotbeyondamaximumsize
9.if(congestionWindowSizesession.getFlowWindowSize()){
.slowStartPhase=false;
.if(packetArrivalRate0){
.packetSendingPeriod=.0/packetArrivalRate;
.}
.else{
.packetSendingPeriod=(double)congestionWindowSize/(roundTripTime+Util.getSYNTimeD());
.}
.}
.
.}else{
.//1.ifitisnotinslowstartphase,setthecongestionwindowsize
.//totheproductofpacketarrivalrateand(rtt+SYN)
.doubleA=packetArrivalRate/.0*(roundTripTime+Util.getSYNTimeD());
.congestionWindowSize=(long)A+;
.if(logger.isLoggable(Level.FINER)){
.logger.finer("receiverate"+packetArrivalRate+"rtt"+roundTripTime+"settowindowsize:"+(A+));
.}
.}
.
.//norateincreaseduringslowstart
.if(slowStartPhase)return;
.
.//norateincrease"immediately"afteraNAK
.if(loss){
.loss=false;
.return;
.}
.
.//4.computetheincreaseinsentpacketsforthenextSYNperiod
.doublenumOfIncreasingPacket=computeNumOfIncreasingPacket();
.
.//5.updatethesendperiod
.doublefactor=Util.getSYNTimeD()/(packetSendingPeriod*numOfIncreasingPacket+Util.getSYNTimeD());
.packetSendingPeriod=factor*packetSendingPeriod;
.//packetSendingPeriod=0.*packetSendingPeriod;
.
.statistics.setSendPeriod(packetSendingPeriod);
.}
On NAK packet received:
1) If it is in slow start phase, set inter-packet interval to
1/recvrate. Slow start ends. Stop.
2) If this NAK starts a new congestion period, increase inter-packet
interval (snd) to snd = snd * 1.; Update AvgNAKNum, reset
NAKCount to 1, and compute DecRandom to a random (average
distribution) number between 1 and AvgNAKNum. Update LastDecSeq.
Stop.
3) If DecCount = 5, and NAKCount == DecCount * DecRandom:
a. Update SND period: SND = SND * 1.;
b. Increase DecCount by 1;
c. Record the current largest sent sequence number (LastDecSeq).
Java代码
复制代码
代码如下:
1./*(non-Javadoc)
2.*@seeudt.CongestionControl#onNAK(java.util.List)
3.*/
4.publicvoidonLoss(ListIntegerlossInfo){
5.loss=true;
6.longfirstBiggestlossSeqNo=lossInfo.get(0);
7.nACKCount++;
8./*1)Ifitisinslowstartphase,setinter-packetintervalto
9.1/recvrate.Slowstartends.Stop.*/
.if(slowStartPhase){
.if(packetArrivalRate0){
.packetSendingPeriod=.0/packetArrivalRate;
.}
.else{
.packetSendingPeriod=congestionWindowSize/(roundTripTime+Util.getSYNTime());
.}
.slowStartPhase=false;
.return;
.}
.
.longcurrentMaxSequenceNumber=session.getSocket().getSender().getCurrentSequenceNumber();
.//2)IfthisNAKstartsanewcongestionepoch
.if(firstBiggestlossSeqNolastDecreaseSeqNo){
.//-increaseinter-packetinterval
.packetSendingPeriod=Math.ceil(packetSendingPeriod*1.);
.//-UpdateAvgNAKNum(theaveragenumberofNAKspercongestion)
.averageNACKNum=(int)Math.ceil(averageNACKNum*0.+nACKCount*0.);
.//-resetNAKCountandDecCountto1,
.nACKCount=1;
.decCount=1;
./*-computeDecRandomtoarandom(averagedistribution)numberbetween1andAvgNAKNum*/
.decreaseRandom=(int)Math.ceil((averageNACKNum-1)*Math.random()+1);
.//-UpdateLastDecSeq
.lastDecreaseSeqNo=currentMaxSequenceNumber;
.//-Stop.
.}
.//*3)IfDecCount=5,andNAKCount==DecCount*DecRandom:
.elseif(decCount=5nACKCount==decCount*decreaseRandom){
.//a.UpdateSNDperiod:SNDSND=SND*1.;
.packetSendingPeriod=Math.ceil(packetSendingPeriod*1.);
.//b.IncreaseDecCountby1;
.decCount++;
.//c.Recordthecurrentlargestsentsequencenumber(LastDecSeq).
.lastDecreaseSeqNo=currentMaxSequenceNumber;
.}
.
.statistics.setSendPeriod(packetSendingPeriod);
.return;
.}
以上就是基于UDP传输协议的流量和拥塞控制的代码,希望能帮到大家,谢谢阅读。rapi蓝牙源码
Windows下C语言多线程实现UDP通信程序recvfrom()函数出现错误:远程主机强迫关闭了一个现有的连接。
在进行Windows下C语言多线程实现UDP通信程序时,遇到recvfrom()函数出现错误的情况。问题在于将recvfrom函数置于一路线程中,而sendto函数置于主线程中。此错误被发现源于Windows socket的一个bug,在UDP Socket发送数据后收到不可达ICMP包时,此错误会在下一次接收时返回,导致recvfrom()函数返回SOCKET_ERROR,错误代码为。
解决此问题的方法之一是直接忽略这个错误,通过在接收数据的代码段中添加条件判断,如if ( == a) continue;这样当接收到错误时,程序会跳过该错误并继续运行。这解决了问题,使得在启动对端程序时能够正常通信。但该方法是否准确以及是否对程序的后续运行有影响,仍需要进一步验证。
另一种网上查询到的解决方案是在sendto函数前添加相应的代码。此方法经过测试,效果良好。通过调整程序结构,使得错误处理更合理,从而确保了通信的稳定性。这为解决recvfrom()函数出现错误提供了一个实用的方法。