WINDOWS下利用QOS实现流量控制

摘要:

限制网络流量的方法包括路由器端限制和本地限制,一般企业采用的是路由器限制的方法,但是并不是所有的路由器都支持流量限制功能。本文尝试解决如下问题:局域网内的机器上都安装一客户端软件,并连接到一内网服务器;客户端软件控制客户机网络流量,服务器负责制定并分发控制规则。本文采用的是Windows系统提供的流量控制功能。

 

一、问题提出及描述

在Windows系统上利用客户端软件控制网络流量,对于内网和外网连接区别对待。如某用户使用BT下载,占用带宽,影响其他同事正常上网,这种情况是需要限制的。而局域网内部应用,则不应受限制。限制外网连接的上传、下载速度,避免造成阻塞,影响正常工作。

 

二、问题分析

问题的关键是网络流量控制,Windows系统本身提供了流量控制功能,看一下MSDN关于Traffic Control的描述:

Traffic Control API

The traffic control application programming interface (TC API), is a programmatic interface to the components that regulate network traffic on local hosts; both from an internal perspective (within the kernel itself), and from a network perspective (prioritization and queuing of packets based on transmission priority).

Traffic control is implicitly invoked through calls made to the QOS API and subsequently serviced by the RSVP service provider (RSVP SP). However, applications that require further or specific control over traffic control can use the TC API. The RSVP Service also uses TC API calls.

Note that the use of functions in the TC API requiresadministrative privilege.

Windows本身提供了流量控制功能,我们要做的就是call TC API.

 

流量控制的原理:

从上面的描述中我们可以看到,Windows提供的Traffic Control使用的是QOS中的RSVP(资源预留)协议。

资源预留(适于综合服务): 根据某个应用对QoS的要求来分配网络资源, 并且服从带宽管理策略 

RSVP 提 供 网 络 资 源 预 留 的 信 令。 尽 管 RSVP 经 常 用 于 单 个 流, 但 也 用 于 聚 合 流 的 资 源 预 留 。

RSVP 是 一 个 信 令 协 议, 它 提 供 建 立 连 接 的 资 源 预 留, 控 制 综 合 业 务, 往 往 在 IP 网 络 上 提 供 仿 真 电 路。 RSVP 是 所 有 QoS 技 术 中 最 复 杂 的 一 种, 与 尽 力 而 为 的 IP 服 务 标 准 差 别 最 大 , 它 能 提 供 最 高 的 QoS 等 级, 使 得 服 务 得 到 保 障、 资 源 分 配 量 化, 服 务 质 量 的 细 微 变 化 能 反 馈 给 支 持 QoS 的 应 用 和 用 户。

 

 

Traffic Control对系统的依赖:

系统需求:Windows 2000及以上版本

系统软件需求:需要客户机安装

各系统测试结果:

系统

需要的组件

默认是否安装

安装后是否可控

Win2000 Professional

Qos数据包安装计划

Windows Server 2003 En

Qos数据包安装计划

Windows XP Professional

Qos数据包安装计划

Windows vista

Qos数据包安装计划

 

如何限制用户访问外网速度而不限制内网访问速度?

第一步限制所有的网段到期望的速率,ip:0.0.0.0,Mask:0.0.0.0

第二步重新设置对内网的限制:如,132.132.0.0,Mask:255.255.0.0

此方法已经过测试,证明可行

 

如何调整速率限制的大小?

The TcModifyFlow function modifies an existing flow. When callingTcModifyFlow, newFlowspec parameters and any traffic control objects should be filled.

 

 

三、问题解决

下面是TC API列表,函数的详细描述请参见MSDN,本文会解释部分用到的关键函数。

 根据调用顺序排序:

TcRegisterClient   // 调用Tc API,必须首先调用这个。注册一个使用TCI(流量控制接口)的客户端

TcEnumerateInterfaces // 枚举可用户流量控制的接口。接口=网卡?待确定

TcOpenInterface   // 打开接口

TcAddFlow           // 添加一个Flow,一个Flow可以看做一个或一类连接(Connection)

TcAddFilter           // 添加一个Filter,Filter是实现流量控制的关键对象,我们将在下文解释

TcDeleteFilter     // 删除Fliter

TcDeleteFlow     // 删除Flow

TcCloseInterface    // 关闭Tc接口

// 下面这些是一些功能函数,对限制流量功能来说并不是必须调用的,详细解释可以查看MSDN。

TcDeregisterClient

TcEnumerateFlows

TcGetFlowName

TcModifyFlow

TcQueryFlow

TcQueryInterface

TcSetFlow

TcSetInterface

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

结合一下代码来详细解释一下程序执行过程。

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

* 函数介绍:限制一个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;  

      QoSFunctions.ClAddFlowCompleteHandler   =   NULL;  

      QoSFunctions.ClDeleteFlowCompleteHandler   =   NULL;

      QoSFunctions.ClModifyFlowCompleteHandler   =   NULL;  

      QoSFunctions.ClNotifyHandler  = (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-> ObjectHdr.ObjectType   =   QOS_OBJECT_DS_CLASS;

      pQOSClass-> ObjectHdr.ObjectLength   =   sizeof(QOS_DS_CLASS);

      pQOSClass-> DSField   =   0x24;

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

      pTRClass-> ObjectHdr.ObjectType   =   QOS_OBJECT_TRAFFIC_CLASS;

      pTRClass-> ObjectHdr.ObjectLength   =   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));  

      GenericFilter.AddressType   =   NDIS_PROTOCOL_ID_TCP_IP;   // TCP/IP

      GenericFilter.PatternSize   =   sizeof(IP_PATTERN);  

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

      GenericFilter.Mask   =   &Mask;  

 

      //  过滤器模式 

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

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

      Pattern.Reserved1   =   0;  

      Pattern.Reserved2   =   0;  

      Pattern.SrcAddr   =   inet_addr( pzSrcIp );  // 源IP

      Pattern.DstAddr   =   inet_addr( pzDstIp );  // 目标IP

      Pattern.tcSrcPort   = htons( nSrcPort );      // 源端口

      Pattern.tcDstPort   = htons( nDstPort );      // 目标端口

      Pattern.ProtocolId   =   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;

      Mask.SrcAddr   =   htonl( 0xFFFFFFFF );

      Mask.DstAddr   =   htonl(0xFFFFFFFF);

      Mask.tcSrcPort   = htons( 0xFFFF );

      Mask.tcDstPort   = htons( 0xFFFF );

      Mask.ProtocolId   =   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;

}

四、示例代码

是一个基于对话框的MFC工程,在Winxp + VC6 + Windows Server 2003 SP1 Platform SDK下编译、运行通过,其他平台未测试。

编译的时候需要安装Windows Platform SDK,我安装的是Windows Server 2003 SP1 Platform SDK。

 

五、附件

附件1

Htm

附件2

Rar

附件3

Txt

附件4

rar

 

六、结束语

以上内容是关于Windows系统中限制网络流量的方法的简单描述,并提供了完整的演示工程代码。

相关概念和函数的描述并不是很详细,不过大部分都可以从MSDN中找到。

实际运行效果以文档中提供的演示工程为准。

 

如有错误,欢迎指正。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
QoS(Quality of Service)即服务质量,是一种网络技术,旨在保证网络中各种应用程序能够得到适当的带宽和网络资源。在网络中,QoS通常指的是流量控制和管理,以确保网络资源按照一定的优先级或条件分配给不同的应用程序和用户。 流量控制QoS的核心,它可以对网络中的数据流进行限制、分类和调度,以确保网络中的各种应用程序都能够得到适当的网络资源。流量控制一般包括以下几个方面: 1. 带宽控制:通过限制数据流的带宽来控制网络中的流量,以确保网络中的各种应用程序都能够得到适当的网络资源。 2. 流量分类:将网络中的数据流按照一定的规则分类,以便对不同的应用程序进行不同的流量控制和管理。 3. 流量调度:对网络中的数据流进行调度,以确保网络中的各种应用程序都能够得到适当的网络资源。 4. 延迟控制:通过控制数据流的延迟来控制网络中的流量,以确保网络中的各种应用程序都能够得到适当的网络资源。 5. 丢包控制:通过控制数据流的丢包率来控制网络中的流量,以确保网络中的各种应用程序都能够得到适当的网络资源。 QoS流量控制和管理在网络中应用广泛,尤其是在网络中存在较大差异的应用程序和用户时,QoS技术可以确保网络中的各种应用程序都能够得到适当的网络资源,从而提高网络的性能和稳定性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值