19.10 Boost Asio 同步文件传输

news2024/11/13 4:29:48

在原生套接字编程中我们介绍了利用文件长度来控制文件传输的方法,本节我们将采用另一种传输方式,我们通过判断字符串是否包含goodbye lyshark关键词来验证文件是否传输结束了,当然了这种传输方式明显没有根据长度传输严谨,但使用这种方式也存在一个有点,那就是无需确定文件长度,因为无需读入文件所以在传输速度上要快一些,尤其是面对大文件时。

服务端代码如下所示,在代码中我们分别封装实现recv_remote_file该函数用于将远程特定目录下的文件拉取到本地目录下,而send_local_file函数则用于将一个本地文件传输到对端主机上,这两个函数都接收三个参数,分别是套接字句柄,本地文件与远程文件的文件路径,在传输时采用了while循环读取发送的实现方式每次传输1024个字节,直到传输结束为止。

#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/array.hpp>

using namespace boost::asio;

// 将远程特定目录下的文件拉取到本地目录
bool recv_remote_file(ip::tcp::socket *socket, std::string remote_file_path, std::string local_file_path)
{
  boost::system::error_code error_code;

  // 发送需要下载的文件,告诉客户端我需要下载的文件路径
  std::string message = remote_file_path;
  bool ref = (*socket).write_some(boost::asio::buffer(message), error_code);
  if (ref == false)
    return false;

  char buffer[1024] = { 0 };

  // 打开文件,准备写入,保存远程文件到本地 
  FILE * fp = fopen(local_file_path.c_str(), "wb");
  if (NULL == fp)
    return false;

  int length = 0;

  // 每次传输1024字节,直到传输全部结束
  while ((length = (*socket).read_some(boost::asio::buffer(buffer, 1024), error_code)) > 0)
  {
    // 判断最后一次是否为结束符号
    if (strncmp(buffer, "goodbye lyshark",15) == 0)
    {
      std::cout << "传输结束,再见了 lyshark" << std::endl;
      fclose(fp);
      return true;
    }

    if (fwrite(buffer, sizeof(char), length, fp) < length)
    {
      std::cout << "写入文件失败" << std::endl;
      break;
    }
    std::cout << "接收字节数: " << length << " Bytes" << std::endl;
    memset(buffer, 0, 1024);
  }

  if (error_code)
  {
    fclose(fp);
    return false;
  }
  fclose(fp);
  return true;
}

// 将本地特定文件发送到远程的特定目录下
bool send_local_file(ip::tcp::socket *socket, std::string local_file_path, std::string remote_file_path)
{
  boost::system::error_code ec;
  char buffer[1024] = { 0 };

  // 发送放入目标位置
  bool ref = (*socket).write_some(boost::asio::buffer(remote_file_path));
  if (ref == false)
    return false;

  // 打开待发送文件
  FILE * fp = fopen(local_file_path.c_str(), "rb");
  if (NULL == fp)
    return false;

  int length = 0;

  // 每次读入1024字节 直到全部读取结束
  while ((length = fread(buffer, sizeof(char), 1024, fp)) > 0)
  {
    bool ref = (*socket).write_some(boost::asio::buffer(buffer, 1024));
    if (ref != false)
    {
      std::cout << "发送字节数: " << length << " Bytes" << std::endl;
      memset(buffer, 0, 1024);
    }
  }

  // 发送结束符
  (*socket).write_some(boost::asio::buffer("goodbye lyshark"));

  if (ec)
  {
    fclose(fp);
    return false;
  }
  fclose(fp);
  return true;
}

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);

  std::cout << "远端IP地址: " << socket.remote_endpoint().address() << std::endl;
  std::cout << "本端IP地址: " << socket.local_endpoint().address() << std::endl;

  // 将远程目录下 c://lyshark.exe 下载到本地的 d://lyshark.exe
  bool recv_ref = recv_remote_file(&socket, "c://lyshark.exe", "d://lyshark.exe");
  std::cout << "下载状态: " << recv_ref << std::endl;

  std::system("pause");

  // 将本地目录中的 d://lyshark.exe 发送到远程 c://test.exe
  bool send_ref = send_local_file(&socket, "d://lyshark.exe", "c://test.exe");
  std::cout << "上传状态: " << send_ref << std::endl;

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

客户端代码代码如下所示,分别实现了两个函数,函数upload_file用于将本地文件上传到服务器端,函数download_file则用于接收服务器端发送过来的文件,过程中同样采用while循环,每次传输1024个字节。

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

using namespace boost::asio;

// 将本地特定文件发送到远程的特定目录下
bool upload_file(ip::tcp::socket *socket)
{
  boost::system::error_code error_code;
  boost::array<char, 4096> buf = { 0 };
  char buffer[1024] = { 0 };

  // 接收要下载文件路径
  size_t len = (*socket).read_some(boost::asio::buffer(buf));
  if (len == 0)
    return false;

  // 打开需要发送的文件
  FILE * fp = fopen(buf.data(), "rb");
  if (NULL == fp)
    return false;

  int length = 0;

  // 每次读入1024字节,直到全部读取结束
  while ((length = fread(buffer, sizeof(char), 1024, fp)) > 0)
  {
    bool ref = (*socket).write_some(boost::asio::buffer(buffer, 1024));
    if (ref != false)
    {
      std::cout << "发送字节数: " << length << " Bytes" << std::endl;
      memset(buffer, 0, 1024);
    }
  }
  // 发送结束符
  (*socket).write_some(boost::asio::buffer("goodbye lyshark"));

  // 如果出现错误直接退出
  if (error_code)
  {
    fclose(fp);
    return false;
  }
  fclose(fp);
  return true;
}

// 获取远程发送过来的文件
bool download_file(ip::tcp::socket *socket)
{
  boost::system::error_code error_code;

  // 读入需要保存文件路径
  char file_path[4096] = { 0 };
  (*socket).read_some(boost::asio::buffer(file_path));

  char buffer[1024] = { 0 };

  //打开文件,准备写入 
  FILE * fp = fopen(file_path, "wb");
  if (NULL == fp)
    return false;

  int length = 0;

  // 每次传输1024字节
  while ((length = (*socket).read_some(boost::asio::buffer(buffer, 1024), error_code)) > 0)
  {
    // 判断最后一次是否为结束符号
    if (strncmp(buffer, "goodbye lyshark",15) == 0)
    {
      std::cout << "传输结束,再见了 lyshark" << std::endl;
      fclose(fp);
      return true;
    }
    if (fwrite(buffer, sizeof(char), length, fp) < length)
    {
      printf("写入文件失败 ! \n");
      break;
    }
    printf("接收字节: %d byte \n", length);
    memset(buffer, 0, 1024);
  }
  if (error_code)
  {
    fclose(fp);
    return true;
  }
  fclose(fp);
  return true;
}

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);

  socket.connect(ep);

  // 该函数对应服务端的 recv_remote_file
  bool upload_ref = upload_file(&socket);
  std::cout << "上传状态: " << upload_ref << std::endl;

  std::system("pause");

  // 该函数对应服务端的 send_local_file
  bool recv_ref = download_file(&socket);
  std::cout << "下载状态: " << recv_ref << std::endl;

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

读者可自行编译并运行上述程序,代码中依次实现了上传与下载功能,如下图所示;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1164331.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

创新工具箱!重塑手机页面原型设计体验

在2024年&#xff0c;随着移动设备的普及和用户对移动体验的要求不断提升&#xff0c;手机页面原型设计工具变得越来越重要。在这篇文章中&#xff0c;我将为您推荐几款在2024年非常流行且值得一试的手机页面原型设计工具。 Pixso Pixso是一款基于云端的协作设计工具&#xf…

输入几个数,分别输出其中的奇数和偶数

这个问题我们只需要设计几个循环嵌套在一起就可以解决&#xff0c;话不多说&#xff0c;我们直接上代码 目录 1.运行代码 2.运行结果 1.运行代码 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<string.h>int main() {int arr[10] {1,2,3,4,5,6,…

【蓝桥杯基础题】星期一

👑专栏内容:蓝桥杯刷题⛪个人主页:子夜的星的主页💕座右铭:前路未远,步履不停目录 一、题目描述二、题目分析三、代码汇总1、C++代码2、Java代码四、总结求解闰年一、题目描述 题目链接:星期一 整个20世纪(1901年1月1日至2000年12月31日之间),一共有多少个星期一…

kvm--网桥搭建

确定需要桥接的网卡 查看ip地址&#xff1a; 这里使用网卡enp125s0f2做桥接网卡 修改网卡配置 操作系统&#xff1a;kylinv10SP1(Tercel) 查看网卡配置文件&#xff1a; cd /etc/sysconfig/network-scripts/ ls 备份网卡文件 cp ifcfg-enp125s0f2 ifcfg-enp125s0f2.bak …

AutoDL 云/本地部署 百川2、GLM2

AutoDL 云上部署 百川2、GLM2 AutoDL 云上部署 百川2、GLM2配置环境体验常见问题huggingface访问不了&#xff0c;使用学术资源加速大文件上传&#xff0c;百度、阿里网盘都可CUDA 空间不足系统盘空间不足省钱绝招软件源 本地部署 百川2、GLM2根据显存大小选模型拉取docker镜像…

Linux编译器vim的使用

文章目录 vim基本概念vim的常用三种模式vim三种模式的相互转换 vim命令模式下的命令集移动光标删除文字剪切/删除复制替换撤销和恢复跳转至指定行 vim底行模式下的命令集 vim基本概念 vim是Linux下的一个多模式的编译器 简单来说就是写代码的工具 不提供编译调试等功能 有语法…

警惕!当心AI诈骗!

本文参照材料有&#xff1a; 鄂尔多斯新闻公众号、澎湃新闻网、搜孤新闻、腾讯网等 AI换脸诈骗实例&#xff08;就发生在近期&#xff09; 事例一&#xff1a; 近期 “AI换脸”新型诈骗频发和你视频对话的可能不是本人&#xff01; 近日&#xff0c;东胜市民李女士遭遇了冒充…

AN动画基础——路径动画

【AN动画基础——路径动画】 路径动画基础使用其他效果沿着路径放大沿路径着色调整到路径 本篇内容&#xff1a;了解路径动画 重点内容&#xff1a;路径动画应用 工 具&#xff1a;Adobe Animate 2022 路径动画 路径动画是一种在动画中沿着一条预设路径进行移动的效果。 路径可…

【Qt控件之QLineEdit】N多种用法及技巧

【Qt控件之QLineEdit】N多种用法及技巧 介绍用法用法1&#xff1a;信号触发 用法2&#xff1a;添加动作用法3&#xff1a;删除光标最侧字符用法4&#xff1a;设置光标位置用法5&#xff1a;删除用法6&#xff1a;选择和取消选择用法7&#xff1a;不为空时是否显示清除按钮用法8…

2023年江西省职业院校技能大赛网络建设与运维赛项省赛样题

2023年江西省职业院校技能大赛 网络建设与运维赛项省赛样题 竞赛说明&#xff1a; 1.禁止携带和使用移动存储设备、计算器、通信工具及参考资料。 2.请根据大赛所提供的比赛环境&#xff0c;检查所列的硬件设备、软件及文档清单、材料清单是否齐全&#xff0c;计算机设备是否能…

Java实验一编程环境使用

1&#xff0e;String类的常用方法&#xff08;StringExample.java&#xff09; package step1;public class StringExample {public static void main(String args[]) {String s1 new String("you are a student");String s2 new String("how are you")…

outlook是什么软件outlook邮箱撤回邮件方法

Outlook是微软公司开发的一款邮件客户端&#xff0c;也是Office办公套件的一部分。它可以与多个电子邮件服务提供商&#xff08;如Outlook.com、Exchange、Gmail等&#xff09;集成&#xff0c;用户可以使用Outlook来发送、接收和管理电子邮件、日历、联系人、任务等信息。本篇…

【好玩的开源项目】Linux系统之部署捕鱼达人经典小游戏

【好玩的开源项目】Linux系统之部署捕鱼达人经典小游戏 一、捕鱼达人小游戏介绍1.1 捕鱼达人小游戏简介1.2 项目地址 二、本次实践介绍2.1 本地环境规划2.2 本次实践介绍 三、安装httpd软件3.1 检查yum仓库3.2 安装httpd软件3.3 启动httpd服务3.4 查看httpd服务3.5 防火墙和sel…

vue-浏览器安装Vue开发者工具

极简插件&#xff1a;下载->开发者模式->拖曳安装->插件详情允许访问文件 网址&#xff1a;https://chrome.zzzmh.cn/index 搜索Vue Devtools 下载下来的安装包先解压 然后点击chrome浏览器的右上角三个点的按钮在里面找到扩展程序这个选项&#xff0c;然后点进去管理…

提示3D标题编辑器仍在运行怎么解决,以及3D标题编辑器怎么使用

在进行视频剪辑时&#xff0c;尤其是剪辑一些带有文字的开场视频&#xff0c;一般都会使用具有立体效果的3D标题&#xff0c;这样制作出来的视频效果不仅好看&#xff0c;还非常的炫酷&#xff0c;但是对于一些刚刚开始接触视频剪辑的小伙伴来说&#xff0c;可能对3D标题还不是…

网工内推 | 大专以上,福利待遇好,IE认证优先(云厂商)

01 主动脉科技有限公司 招聘岗位&#xff1a;网络工程师 职责描述&#xff1a; 1.负责云计算&#xff0c;IDC&#xff0c;BGP网络&#xff0c;通过团队协作&#xff0c;构建云业务后台技术支持服务体系。 2.通过工单、其他通讯工具等线上方式完成对客户的实施售后支持&#x…

后端开发基本步骤(未完成继续写中)

1.使用spring initializr创建项目 注意&#xff1a;然后低下提供的依赖可用可不用&#xff0c;先不用&#xff0c;后边Maven统一配置依赖&#xff0c; 2.导入依赖 <!-- web --> <dependency><groupId>org.springframework.boot</groupId><artifa…

OpenCV官方教程中文版 —— 图像修复

OpenCV官方教程中文版 —— 图像修复 前言一、基础二、代码三、更多资源 前言 本节我们将要学习&#xff1a; • 使用修补技术去除老照片中小的噪音和划痕 • 使用 OpenCV 中与修补技术相关的函数 一、基础 在我们每个人的家中可能都会几张退化的老照片&#xff0c;有时候…

初学Redis简介以及入门

&#x1f3c5;我是默&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; ​ &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Linux》。&#x1f3af;&#x1f3af; &#x1f680;无论你是编程小白&#xff0c;还是有一定基础的程序员&#xff0c;这…

数据结构与算法C语言版学习笔记(1)-绪论

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、数据结构的研究内容二、基本概念与术语1.数据与数据元素2.数据结构逻辑结构的种类存储结构的种类 三、算法1.什么是算法&#xff1f;算法的描述2.一个算法要具备…