IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> Windows 批量添加删除路由资源性能优化 -> 正文阅读

[网络协议]Windows 批量添加删除路由资源性能优化

? 首先,本文只涉及如何优化Windows批量添加删除路由资源的速度优化。

?

基于虚拟网卡来实现虚拟网络的组建的架构图如下所示:

图片来自网络

起因:

? 一般来说,私有网络的一个资源对应本地的一条路由(比如:www.example.com,就是一条或者多条ip地址的路由资源),当然,你也可以推送一个网段,这样操作比较简单,但是存在一定的安全隐患,因为你将整个私有网络的网段推送到客户端,这样客户端连上之后就可以访问整个网段的资源,为了安全起见,一般不会推送单个资源地址。

? 在早些的开源的代码实现中,可以看到,拨号客户端通过调用本地系统的route.exe进程来控制路由资源的增删操作。

? 拨号客户端在连接到服务器之后,调用系统route.exe进程,根据服务端推送的资源依次添加路由,资源少的时候建立连接的速度还可以,但是随着这些资源的壮大,建立连接时的耗时就变得无法忍受了。

通过查找资源,找到了一个号称秒级别的添加千条路由的方案:

rundll32.exe cmroute.dll,SetRoutes /STATIC_FILE_NAME addchnroutes.txt

传送门

? 通过测试发现,这个方式添加路由的速度相当快,本着对未知技术的探索,对cmroute代码实现进行深究?cmroute源码实现?

深入探索:

? 从源码中发现,cmroute.dll中使用的添加路由的方式是通过调用iphlpapi.dll(CreateIpForwardEntryDeleteIpForwardEntryGetIpForwardTable)接口来实现,深入iphlpapi.dll这些个接口的实现,这些接口直接操作系统的驱动程序

#define DD_TCP_DEVICE_NAME ? ? ?L"\\Device\\Tcp

来实现路由资源的增删。

? 调用接口和进程两者的调用方式,相信大家不需要测试也知道哪个性能更好一些,在这里还是简单的进行了一下对路由表操作的性能对比分析, 详细如下对254条路由表进行添加测试操作分析:

测试类型测试数量总耗时(s)平均耗时(t/s)
命令行25443.45050.171065
API2540.0119894.72008e-05

从上面的比对上来看,命令行方式1秒大概添加5~6条策略,而api方式1秒大概添加2.5w左右相差几个数量级,可以看出使用api方式添加路由策略还是很有优势的。

后续:

在看了最新的开源的代码后发现,2020年9月份已经支持api的方式,但是使用的是CreateIpForwardEntry2v2版本的api在vista及以后版本之后才支持

代码片段实现参考(需要管理员权限运行):

//测试耗时计算
struct time_overhead {
  time_overhead(const int times)
      : times(times), start(std::chrono::high_resolution_clock::now()) {}
  ~time_overhead() {
    std::chrono::duration<double> elapsed =
        std::chrono::high_resolution_clock::now() - start;
    std::cout << "run " << times << " times in " << elapsed.count()
              << "s, average speed "
              << static_cast<double>(elapsed.count() / times) << "t/s \n";
  }

private:
  const int times;
  std::chrono::steady_clock::time_point start;
};


// 为了获取默认路由下一条地址
{
 unsigned int i;
  dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
  if (dwStatus == ERROR_INSUFFICIENT_BUFFER) {
    buffer.resize(dwSize);
    if (!(pIpForwardTable =
              reinterpret_cast<PMIB_IPFORWARDTABLE>(&buffer[0]))) {
      return -1;
    }
    dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
  }

  if (dwStatus != ERROR_SUCCESS) {
    return -1;
  }

  std::string nethop;
  for (i = 0; i < pIpForwardTable->dwNumEntries; i++) {
    if (pIpForwardTable->table[i].dwForwardDest == 0) { //找到默认网关地址
      in_addr tmp;
      tmp.S_un.S_addr = pIpForwardTable->table[i].dwForwardNextHop;
      nethop = inet_ntoa(tmp);
      break;
    }
  }

  if (nethop.empty()) {
    return -1;
  }
}

// 命令行添加路由
{
  std::vector<std::string> route_cmds;
  for (int i = 1; i < 255; i++) {
    route_cmds.emplace_back("route.exe ADD 192.168.1." + std::to_string(i) +
                            " mask MASK 255.255.255.255 " + nethop +
                            " > NUL 2>&1");
  }

  {
    time_overhead to(route_cmds.size());
    for (auto &item : route_cmds) {
      system(item.c_str()); //命令行方式添加
    }
  }
}

// api方式添加
{
  int mask = ConvertSzToIP("255.255.255.255"); // from cmroute
  int next_hop = ConvertSzToIP(nethop); // from cmroute
  for (int i = 1; i < api_dests.size(); i++) {
    MIB_IPFORWARDROW route = {0};
    route.dwForwardDest = api_dests[i];
    route.dwForwardIfIndex = 7;
    route.dwForwardMask = mask;
    route.dwForwardMetric1 = 281;
    route.dwForwardNextHop = next_hop;

    route.dwForwardPolicy = 0;
    route.dwForwardNextHopAS = 0;
    route.dwForwardType = 3;
    route.dwForwardProto = 3;
    route.dwForwardAge = INFINITE;
    route.dwForwardMetric2 = 0xFFFFFFFF;
    route.dwForwardMetric3 = 0xFFFFFFFF;
    route.dwForwardMetric4 = 0xFFFFFFFF;
    route.dwForwardMetric5 = 0xFFFFFFFF;

    DWORD r = DeleteIpForwardEntry(&route);
    if (ERROR_SUCCESS != r) {
      std::cout << r << "\n";
      return -1;
    }
  }
}

注:如有侵权,请联系作者




?

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章           查看所有文章
加:2021-10-29 13:25:46  更:2021-10-29 13:26:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:42:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码