WINDOWS下利用QOS实现流量控制

时间:2025-03-27 21:59:32

/******************************************************************

* 函数介绍:限制一个Connection的网络流量

* 输入参数:nProtocol:要限制流量的协议类型

            pzSrcIp:源IP

                    nSrcPort:源端口

                    pzDstIp:目标IP

                    nDstPort:目标端口

                    nTraffic:限制流量

* 输出参数:

* 返回值  :成功返回0;失败返回错误码

*******************************************************************/

注意:设置网段流量限制的函数和这个函数大体相同

int CTrafficControl::AddTrafficControl(

                                                                     int nProtocol,

                                                                     const char *pzSrcIp,

                                                                     const int nSrcPort,

                                                                     const char *pzDstIp,

                                                                     const int nDstPort,

                                                                     int nTraffic

                                                                 )

{

      HANDLE   ClientHandle;  

      HANDLE   ifcHandle;  

      HANDLE   flowHandle;  

      HANDLE   FilterHandle;

 

   // QOS函数列表,处理各种事件通知回调函数

      TCI_CLIENT_FUNC_LIST   QoSFunctions;  

         =   NULL;  

         =   NULL;

         =   NULL;  

       = (TCI_NOTIFY_HANDLER)MyClNotifyHandler;

     

      // 注册Client,获取Client句柄

      long   result   =   TcRegisterClient(CURRENT_TCI_VERSION,   NULL,   &QoSFunctions   ,   &ClientHandle);

      if( NO_ERROR != result )

      {

             //cout << "TcRegisterClient error" << endl;

             return result;

      }

 

      // 获取TC接口。枚举接口->根据接口名称打开接口

      TC_IFC_DESCRIPTOR   InterfaceBuffer[40];  

      PTC_IFC_DESCRIPTOR   pInterfaceBuffer   =   &InterfaceBuffer[0];  

      ULONG   BufferSize   =   40 * sizeof(TC_IFC_DESCRIPTOR);  

      result   =   TcEnumerateInterfaces(ClientHandle,   &BufferSize,   pInterfaceBuffer);  

      if( NO_ERROR != result )

      {

             //cout << "TcEnumerateInterfaces error:" << result << endl;

             return result;

      }

 

      // 打开接口。注1:项目编码请使用Unicode编码,否则这里会出错,出现ERROR_NOT_FOUND找不到接口的错误。

      result   =   TcOpenInterface( InterfaceBuffer[0].pInterfaceName,   ClientHandle,   NULL,   &ifcHandle   );

      if( NO_ERROR != result )

      {

             //cout << "TcOpenInterface error:" << result << endl;

             return result;

      }

 

      // 创建一个Flow,下面是关键代码

      int   curSize   =   sizeof(TC_GEN_FLOW)   +  sizeof(QOS_DS_CLASS)   +   sizeof(QOS_TRAFFIC_CLASS)   +   sizeof(QOS_OBJECT_HDR);

      char   *bufFlow   =   new   char[curSize];  

      PTC_GEN_FLOW   newFlow   =   (   PTC_GEN_FLOW   )bufFlow;  

      LPQOS_OBJECT_HDR   objHdr   =   NULL;

 

      // 设置FlowerSpec属性. SetFlowSpec函数实现参见附件中的代码

      FLOWSPEC sendFlowspec, recvFlowspec;

      SetFlowSpec( sendFlowspec, nTraffic, SERVICETYPE_QUALITATIVE );

      SetFlowSpec( recvFlowspec, nTraffic, SERVICETYPE_QUALITATIVE );

     newFlow->SendingFlowspec = sendFlowspec;

      newFlow->ReceivingFlowspec = recvFlowspec;

 

      newFlow-> TcObjectsLength   =   sizeof(QOS_DS_CLASS)   +   sizeof(QOS_TRAFFIC_CLASS)   +   sizeof(QOS_OBJECT_HDR);  

       

      LPQOS_DS_CLASS   pQOSClass   =   (LPQOS_DS_CLASS)(&(newFlow-> TcObjects[0])   );

      pQOSClass->    =   QOS_OBJECT_DS_CLASS;

      pQOSClass->    =   sizeof(QOS_DS_CLASS);

      pQOSClass-> DSField   =   0x24;

      LPQOS_TRAFFIC_CLASS   pTRClass   =   (LPQOS_TRAFFIC_CLASS)((char*)&(newFlow-> TcObjects[0])+   sizeof(QOS_DS_CLASS));

      pTRClass->    =   QOS_OBJECT_TRAFFIC_CLASS;

      pTRClass->    =   sizeof(QOS_TRAFFIC_CLASS);

      pTRClass-> TrafficClass   =   0x3;

      objHdr   =   (LPQOS_OBJECT_HDR)((char *)&(newFlow-> TcObjects[0])   +   sizeof(QOS_DS_CLASS)   +   sizeof   (QOS_TRAFFIC_CLASS));

      objHdr-> ObjectType   =   QOS_OBJECT_END_OF_LIST;

      objHdr-> ObjectLength   =   sizeof(QOS_OBJECT_HDR);

   // 添加Flow到打开的接口中。

   // 注意,FlowSpec设置错误会导致这里添加失败。相关规则请参见MSDN中FLOWSPEC的解释

      result = TcAddFlow( ifcHandle,   /*ClientHandle*/NULL,   0,   newFlow,   &flowHandle   );

      if( NO_ERROR != result )

      {

             //cout << "TcAddFlow Error::" << result << endl;

             return result;

      }

 

      // 创建Filter。

   // Flow设定了流量的限制,Filter设定需要限制流量的条件

      TC_GEN_FILTER   GenericFilter;

      IP_PATTERN   Pattern,   Mask;

      memset(&Pattern,0,sizeof(IP_PATTERN));  

      memset(&Mask,0,sizeof(IP_PATTERN));  

         =   NDIS_PROTOCOL_ID_TCP_IP;   // TCP/IP

         =   sizeof(IP_PATTERN);  

         =   &Pattern;   //   pattern   to   match,   defined   below  

         =   &Mask;  

 

      //  过滤器模式 

   // 根据源、目标ip和端口,我们可以过滤到一个特定的连接。

   // 如果是过滤一个网段,需要用到Mask参数。

      Pattern.Reserved1   =   0;  

      Pattern.Reserved2   =   0;  

         =   inet_addr( pzSrcIp );  // 源IP

         =   inet_addr( pzDstIp );  // 目标IP

         = htons( nSrcPort );      // 源端口

         = htons( nDstPort );      // 目标端口

         =   nProtocol;         // 协议类型。TCP or UDP or else

      Pattern.Reserved3[0]   =   0;

      Pattern.Reserved3[1]   =   0;

      Pattern.Reserved3[2]   =   0;

 

      // 掩码。设置Pattern中哪些位是有效的,也就是IP地址中的掩码

   // 如要限制212.73.0.0这个网段与本地之间的流量,掩码设置为255.255.0.0

      Mask.Reserved1   =   0;

      Mask.Reserved2   =   0;

         =   htonl( 0xFFFFFFFF );

         =   htonl(0xFFFFFFFF);

         = htons( 0xFFFF );

         = htons( 0xFFFF );

         =   nProtocol;

      Mask.Reserved3[0]   =   0;

      Mask.Reserved3[1]   =   0;

      result   =   TcAddFilter(flowHandle,   &GenericFilter,   &FilterHandle); 

      if( NO_ERROR != result )

      {

             //cout << "TcAddFilter error:" << result << endl;

             return result;

      }

     

      return result;

}