网上找遍了也没找到关于异步非阻塞Socket的限速资料,于是,自己写了一份
限速100M/S,误差15M/S
限速50M/S,误差5M/S
限速10M/S,误差0.3M/S
限速5M/S,误差0.02M/S
限速越小,精度越准
function TJsTCPContext.PostWSARecvEvent(IoReQuest:TJsIoReQuest;var ErrorCode:Cardinal):Boolean;
var dwFlags,dwSize:Cardinal;
UseSleep:Boolean;
SleepTime,SleepStartTime,SleepEndTime,i:Int64;
begin
ErrorCode:=0;
Result:=not Disconnecting;
if not Result then Exit;
dwFlags:=0;
dwSize:=0;
IoReQuest.SetupRead;
IoReQuest.SetOperation(IRecv);
IoReQuest.Socket:=FSocket;
IoReQuest.Context:=Self;
QueryPerformanceCounter(SpeedTotal.RecvEndTime);
if SpeedTotal.Limit_Recv_Speed<>0 then begin
(*
限速小于10M/S时,使用休眠,减少CPU占用,提升准确度(大量Socket同时传输时,会影响吞吐量)
Sleep精度太大,超过10M时,会影响计算结果,导致结果偏差过大
限速大于10M/S时,不使用休眠,但会增加CPU占用
*)
UseSleep:=SpeedTotal.Limit_Recv_Speed<=(1024*1024*10);
if UseSleep then begin
QueryPerformanceCounter(SleepStartTime);
uSleep(1);
QueryPerformanceCounter(SleepEndTime);
SleepTime:=Trunc((SleepEndTime-SleepStartTime)*1000*1000/iFreq);
end;
//接收一次使用多少微秒
SpeedTotal.RecvUseTime:=Trunc((SpeedTotal.RecvEndTime-SpeedTotal.RecvStartTime)*1000*1000/iFreq);
if UseSleep then
i:=Trunc((SpeedTotal.Limit_Recv_Speed/(1000*1000))*(SpeedTotal.RecvUseTime+SleepTime))
else
//根据限速条件,估算每次接收要准备多大的缓冲区,才能达到限速上限
i:=Trunc((SpeedTotal.Limit_Recv_Speed/(1000*1000))*(SpeedTotal.RecvUseTime));
//本次接收大小=(限速大小/(1000000微秒,即1秒))*接收一次的微秒耗时
if (i<=0) then i:=1
else if (i>Max_PackSize) then
i:=Max_PackSize;
IoReQuest.FWSABuf.len:=i;
end;
QueryPerformanceCounter(SpeedTotal.RecvStartTime);
Result:=WSARecv(FSocket,@IoReQuest.FWSABuf,1,dwSize,dwFlags,PWSAOverlapped(@IoReQuest.IOData),nil)<>Socket_Error;
if not Result then begin
ErrorCode:=WSAGetLastError;
Result:=ErrorCode=WSA_IO_PENDING;
end;
if Result then begin
{$IFDEF Calc_IO_Count}
InterlockedIncrement(Recv_IO_Count);
{$ENDIF}
InterlockedIncrement(Pending_IO_Count);
end;
end;