19.11 Boost Asio 获取远程目录

简介: 远程目录列表的获取也是一种很常用的功能,通常在远程控制软件中都存在此类功能,实现此功能可以通过`filesystem.hpp`库中的`directory_iterator`迭代器来做,该迭代器用于遍历目录中的文件和子目录,它允许开发者轻松遍历目录层次结构并对遇到的文件和目录执行各种操作。

远程目录列表的获取也是一种很常用的功能,通常在远程控制软件中都存在此类功能,实现此功能可以通过filesystem.hpp库中的directory_iterator迭代器来做,该迭代器用于遍历目录中的文件和子目录,它允许开发者轻松遍历目录层次结构并对遇到的文件和目录执行各种操作。

使用directory_iterator构造函数创建一个迭代器,该迭代器指向目录中的第一个条目。然后,我们使用一个范围for循环来遍历目录中的每个文件和目录,并使用pos->path().string()方法即可得到该目录下的文件路径。

当然,directory_iterator仅遍历目录的直接子文件夹。如果想遍历目录层次结构中的所有文件和目录,则需要改用recursive_directory_iterator来实现递归遍历,或者自行拼接路径完成遍历。

服务端代码实现如下,在代码中我们通过write_some发送需要获取远程目录字符串,接着通过调用一次read_some接收一次需要循环的次数,当收到客户端传来的目录列表数量后,则可以在循环内依次调用read_some函数读取数据,并格式化为CatalogData类型,并输出其变量中的数据。

#include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/asio.hpp>

// 定义结构体,将完整数据放入结构体中
typedef struct
{
   
   
  char file_path[2048];
  bool is_directory;
  long file_size;
}CatalogData;

using namespace std;
using namespace boost;
using namespace boost::asio;

CatalogData ptr;

int main(int argc, char* argv[])
{
   
   
  io_service io_service;
  ip::tcp::acceptor acceptor(io_service, ip::tcp::endpoint(ip::tcp::v4(), 6666));
  ip::tcp::socket socket(io_service);

  acceptor.accept(socket);
  boost::system::error_code error_code;

  // 发送需要获取的目录
  socket.write_some(boost::asio::buffer("d://lyshark"), error_code);

  // 接收文件数量
  char recv_count[1024] = {
   
    0 };
  size_t len = socket.read_some(boost::asio::buffer(recv_count), error_code);
  std::cout << "接收到数量: " << recv_count << std::endl;

  // 判断如果数量大于等于1则需要循环获取
  int for_count = lexical_cast<int>(recv_count);
  if (for_count >= 1)
  {
   
   
    // 循环接收目录
    for (int x = 0; x < for_count; x++)
    {
   
   
      // 准备接收缓冲区,以及接收数据包
      char recv_catalogdata[sizeof(CatalogData)] = {
   
    0 };
      socket.read_some(boost::asio::buffer(recv_catalogdata, sizeof(CatalogData)), error_code);

      // 将收到的字节序转换为CatalogData结构体
      CatalogData *data = (CatalogData *)recv_catalogdata;

      std::cout << "文件路径: " << data->file_path
        << "是否为目录: " << data->is_directory
        << "文件大小: " << data->file_size
        << std::endl;

      memset(recv_catalogdata, 0, sizeof(CatalogData));
    }
  }

  std::system("pause");
  return 0;
}

客户端代码实现如下,相对于服务端客户端的实现则变得复杂一些,在代码中首先通过read_some函数调用获取到服务器端传来的目录C://usr信息,接着直接调用GetFileState函数并以此获取到当前目录下的文件列表信息,并将此信息存储到send_buffer容器内存储,接着再次调用write_some发送此容器内有多少行数据,最后通过使用循环的方式依次write_some发送send_catalogdata文件列表,直到全部发送结束则退出程序。

#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <boost/filesystem.hpp>
#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>

using namespace std;
using namespace boost;
using namespace boost::asio;
using namespace boost::filesystem;

// 定义结构体,将完整数据放入结构体中
typedef struct
{
   
   
  char file_path[2048];
  bool is_directory;
  long file_size;
}CatalogData;

// 利用流获取文件大小
long GetFileSize(std::string filename)
{
   
   
  long ref_kb;
  std::ifstream ptr(filename, std::ios::in | std::ios::binary);

  if (ptr.is_open() == true)
  {
   
   
    ptr.seekg(0, std::ios::end);   // 移动到末尾
    ref_kb = ptr.tellg();          // 获取字节数
    ptr.close();
    return ref_kb;
  }
  return 0;
}

// 遍历文件函数,并将结果存入RefVect
void GetFilePath(const string& pathName, std::vector <std::string> &RefVect)
{
   
   
  directory_iterator end;
  for (directory_iterator pos(pathName); pos != end; ++pos)
  {
   
   
    RefVect.push_back(pos->path().string());
  }
}

// 获取到当前目录详细信息,并依次取出数据
std::vector<CatalogData> GetFileState(const string& pathName)
{
   
   
  std::vector < std::string > ref_file_path;
  GetFilePath(pathName,ref_file_path);

  // 循环获取目录属性
  std::vector<CatalogData> ref_date;
  for (int x = 0; x < ref_file_path.size(); x++)
  {
   
   
    CatalogData ptr;
    // 判断如果是目录,则不计算文件大小
    if (is_directory(ref_file_path[x]))
    {
   
   
      ptr.is_directory = true;
      ptr.file_size = 0;
      strcpy(ptr.file_path, ref_file_path[x].c_str());
    }
    // 如果是文件则计算大小
    else
    {
   
   
      ptr.is_directory = false;
      ptr.file_size = GetFileSize(ref_file_path[x]);
      strcpy(ptr.file_path, ref_file_path[x].c_str());
    }
    // 依次放入容器
    ref_date.push_back(ptr);
  }
  return ref_date;
}

CatalogData ptr;

int main(int argc, char *argv[])
{
   
   
  io_service io_service;
  ip::tcp::socket socket(io_service);
  ip::tcp::endpoint ep(ip::address_v4::from_string("127.0.0.1"), 6666);

  boost::system::error_code error_code;
  socket.connect(ep, error_code);

  // 接收需要获取的目录地址
  char recv_buf[1024] = {
   
    0 };
  size_t len = socket.read_some(boost::asio::buffer(recv_buf), error_code);
  std::cout << "服务端需要获取: " << recv_buf << std::endl;

  // 判断目录是否存在,存在则执行遍历目录
  if (filesystem::exists(recv_buf))
  {
   
   
    std::vector<CatalogData> send_buffer;

    send_buffer = GetFileState(recv_buf);
    // 判断如果获取到了目录,则发送目录个数
    if (send_buffer.size() > 0)
    {
   
   
      // 发送目录总数
      std::string send_count = lexical_cast<std::string>(send_buffer.size());
      std::cout << "获取到的目录文件数量: " << send_count << std::endl;
      socket.write_some(boost::asio::buffer(send_count), error_code);
    }

    // 开始循环发送目录
    for (int x = 0; x < send_buffer.size(); x ++)
    {
   
   
      // 填充局部结构并发送
      char send_catalogdata[sizeof(CatalogData)] = {
   
    0 };

      // 拷贝将send_buffer依次赋值到ptr指针上
      strcpy(ptr.file_path, send_buffer[x].file_path);
      ptr.is_directory = send_buffer[x].is_directory;
      ptr.file_size = send_buffer[x].file_size;

      // 将字节序拷贝到send_catalogdata中
      memcpy(send_catalogdata, &ptr, sizeof(CatalogData));

      // 开始发送字节序
      socket.write_some(boost::asio::buffer(send_catalogdata), error_code);
      memset(send_catalogdata, 0, sizeof(CatalogData));
    }
  }

  std::system("pause");
  return 0;
}

至此读者可自行编译上述代码,并以此先运行服务端程序,接着再运行客户端程序,此时即可获取到远程主机中d://lyshark目录下的所有文件信息,文件属性,以及文件大小,输出效果如下图所示;

相关文章
|
6月前
|
C语言 C++
boost库asio编译及配置
boost库asio编译及配置
243 0
19.4 Boost Asio 远程命令执行
命令执行机制的实现与原生套接字通信一致,仅仅只是在调用时采用了Boost通用接口,在服务端中我们通过封装实现一个`run_command`函数,该函数用于发送一个字符串命令,并循环等待接收客户端返回的字符串,当接收到结束标志`goodbye lyshark`时则说明数据传输完成则退出,客户端使用`exec_command`函数,该函数通过`_popen`函数执行一条命令,并循环`fgets`读取字符串发送给服务端,最终传输一个结束标志完成通信。
51 0
19.4 Boost Asio 远程命令执行
19.10 Boost Asio 同步文件传输
在原生套接字编程中我们介绍了利用文件长度来控制文件传输的方法,本节我们将采用另一种传输方式,我们通过判断字符串是否包含`goodbye lyshark`关键词来验证文件是否传输结束了,当然了这种传输方式明显没有根据长度传输严谨,但使用这种方式也存在一个有点,那就是无需确定文件长度,因为无需读入文件所以在传输速度上要快一些,尤其是面对大文件时。服务端代码如下所示,在代码中我们分别封装实现`recv_remote_file`该函数用于将远程特定目录下的文件拉取到本地目录下,而`send_local_file`函数则用于将一个本地文件传输到对端主机上,这两个函数都接收三个参数,分别是套接字句柄,本地
99 0
19.10 Boost Asio 同步文件传输
|
存储 Windows
asio源码解析
基于1.57版本
193 0
asio源码解析
|
12月前
|
容器
19.12 Boost Asio 获取远程进程
远程进程遍历功能实现原理与远程目录传输完全一致,唯一的区别在于远程进程枚举中使用`EnumProcess`函数枚举当前系统下所有活动进程,枚举结束后函数返回一个`PROCESSENTRY32`类型的容器,其中的每一个成员都是一个进程信息,只需要对该容器进行动态遍历即可得到所有的远程主机列表。
60 0
19.12 Boost Asio 获取远程进程
|
存储 算法 C++
4.5 C++ Boost 文件目录操作库
在Boost库出现之前,C++对于文件和目录的操作需要调用底层接口操作,非常不友好,而且不同平台的接口差异也很大,难以移植。但是,Boost库中的filesystem库可以解决这个问题,它是一个可移植的文件系统操作库,可以跨平台的操作目录、文件等,并提供了友好的操作方法,并且在不失性能的情况下提供了良好的抽象和封装。Boost 库是一个由C/C++语言的开发者创建并更新维护的开源类库,其提供了许多功能强大的程序库和工具,用于开发高质量、可移植、高效的C应用程序。Boost库可以作为标准C库的后备,通常被称为准标准库,是C标准化进程的重要开发引擎之一。使用Boost库可以加速C应用程序的开发过程
146 0
|
存储 网络协议 API
4.9 C++ Boost 命令行解析库
命令行解析库是一种用于简化处理命令行参数的工具,它可以帮助开发者更方便地解析命令行参数并提供适当的帮助信息。C++语言中,常用的命令行解析库有许多,通过本文的学习,读者可以了解不同的命令行解析库和它们在C++项目中的应用,从而更加灵活和高效地处理命令行参数。
165 0
|
网络协议 数据格式 JSON
使用boost::asio库实现多个子进程监听同一个端口
class session_http { public: session_http(boost::asio::io_context &io) : socket_(io) {}; void run(boost::asi...
2386 0
|
网络协议 编译器 消息中间件