20.8 OpenSSL 套接字SSL传输文件

有了上面的基础那么传输文件的实现就变得简单了,在传输时通常我们需要打开文件,并每次读入1024个字节的数据包,通过SSL加密传输即可,此处的文件传输功能在原生套接字章节中也进行过详细讲解,此处我们还是使用原来的密钥对,实现一个服务端等待客户端上传,当客户端连接到服务端后则开始传输文件,服务端接收文件的功能。

服务端代码部分,此处我们只需要实现一个DownloadFile函数,该函数接收一个SSL套接字,与保存文件路径即可,其他部分同上。

#include <WinSock2.h>
#include <iostream>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/pem.h>
#include <openssl/crypto.h>

extern "C"
{
#include <openssl/applink.c>
}

#pragma comment(lib, "WS2_32.lib")
#pragma comment(lib,"libssl.lib")
#pragma comment(lib,"libcrypto.lib")

#define MAXBUF 1024

// 从路径中获取当前文件名
char* GetFileName(char* Path)
{
  if (strchr(Path, '\\'))
  {
    char ch = '\\';
    char* ref = strrchr(Path, ch) + 1;
    return ref;
  }
  else
  {
    char ch = '/';
    char* ref = strrchr(Path, ch) + 1;
    return ref;
  }
}

// 下载文件到当前目录
// 传入套接字句柄,以及放置根目录
void DownloadFile(SSL* ptr, const char* RootPath)
{
  int FileSize = 0;
  char FilePath[1024] = { 0 };
  char buffer[1024] = { 0 };

  // 接收文件长度
  SSL_read(ptr, &FileSize, 4);

  // 接收文件路径
  SSL_read(ptr, FilePath, 1024);

  // 获取到文件名
  char* FileName = GetFileName(FilePath);

  // 拼接路径
  char sz[1024] = { 0 };
  strcpy(sz, RootPath);
  strcat(sz, FileName);
  std::cout << sz << std::endl;

  // 保存文件到当前目录
  FILE* pointer = fopen(sz, "wb");

  if (pointer != NULL)
  {
    DWORD length = 0;
    DWORD total_length = 0;

    // 循环接收字节数据,每次接收1024字节
    while ((length = SSL_read(ptr, buffer, 1024)) > 0)
    {
      // 写出文件并判断是否写出成功
      if (fwrite(buffer, sizeof(char), length, pointer) < length)
      {
        break;
      }

      // 每次累加递增
      total_length += length;
      memset(buffer, 0, 1024);

      // 判断文件长度是否全部接收完毕
      if (total_length >= FileSize)
      {
        std::cout << "[传输完成] " << total_length << std::endl;
        fclose(pointer);
        return;
      }
    }
    fclose(pointer);
  }
}

int main(int argc, char** argv)
{
  SOCKET sockfd, new_fd;
  struct sockaddr_in socket_ptr, their_addr;
  char buf[MAXBUF + 1];
  SSL_CTX* ctx;

  SSL_library_init();
  OpenSSL_add_all_algorithms();
  SSL_load_error_strings();

  ctx = SSL_CTX_new(SSLv23_server_method());
  if (ctx == NULL)
  {
    return 0;
  }

  if (SSL_CTX_use_certificate_file(ctx, "d://cacert.pem", SSL_FILETYPE_PEM) <= 0)
  {
    return 0;
  }

  if (SSL_CTX_use_PrivateKey_file(ctx, "d://privkey.pem", SSL_FILETYPE_PEM) <= 0)
  {
    return 0;
  }

  if (!SSL_CTX_check_private_key(ctx))
  {
    return 0;
  }

  WSADATA wsaData;

  WSAStartup(MAKEWORD(2, 2), &wsaData);
  if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
  {
    WSACleanup();
    return 0;
  }

  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  {
    return 0;
  }

  socket_ptr.sin_family = AF_INET;
  socket_ptr.sin_addr.s_addr = inet_addr("127.0.0.1");
  socket_ptr.sin_port = htons(9999);

  if (bind(sockfd, (struct sockaddr*)&socket_ptr, sizeof(struct sockaddr)) == -1)
  {
    return 0;
  }
  if (listen(sockfd, 10) == -1)
  {
    return 0;
  }

  while (1)
  {
    SSL* ssl;
    int len = sizeof(struct sockaddr);
    if ((new_fd = accept(sockfd, (struct sockaddr*)&their_addr, &len)) != -1)
    {
      printf("客户端地址: %s --> 端口: %d --> 套接字: %d \n", inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port), new_fd);
    }

    ssl = SSL_new(ctx);
    SSL_set_fd(ssl, new_fd);
    if (SSL_accept(ssl) == -1)
    {
      closesocket(new_fd);
      break;
    }

    // 调用下载文件函数
    DownloadFile(ssl, "d://lyshark/");

  finish:
    SSL_shutdown(ssl);
    SSL_free(ssl);
    closesocket(new_fd);
  }

  closesocket(sockfd);
  WSACleanup();
  SSL_CTX_free(ctx);

  system("pause");
  return 0;
}

客户端部分,同样代码中只需要实现一个UploadFile函数,该函数用于发送本地文件到远程,其他部分同上。

#include <WinSock2.h>
#include <iostream>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/pem.h>
#include <openssl/crypto.h>

extern "C"
{
#include <openssl/applink.c>
}

#pragma comment(lib, "WS2_32.lib")
#pragma comment(lib,"libssl.lib")
#pragma comment(lib,"libcrypto.lib")

#define MAXBUF 1024

// 获取文件大小
int GetFileSize(std::string FileName)
{
  FILE* pointer = NULL;
  pointer = fopen(FileName.c_str(), "rb");
  if (pointer != NULL)
  {
    fseek(pointer, 0, SEEK_END);
    int size = ftell(pointer);
    fclose(pointer);
    return size;
  }
  return 0;
}

// 上传文件,传入socket套接字句柄,需要发送的文件路径
void UploadFile(SSL* ptr, const char* FilePath)
{
  int FileSize = GetFileSize(FilePath);
  char buffer[1024] = { 0 };

  // 发送文件长度
  SSL_write(ptr, &FileSize, 4);

  // 发送完整文件路径
  SSL_write(ptr, FilePath, strlen(FilePath));
  FILE* pointer = fopen(FilePath, "rb");
  if (pointer != NULL)
  {
    int length = 0;
    DWORD total_length = 0;

    while ((length = fread(buffer, sizeof(char), 1024, pointer)) > 0)
    {
      SSL_write(ptr, buffer, length);
      memset(buffer, 0, 1024);
    }
  }
}

int main(int argc, char** argv)
{
  int sockfd, len;
  struct sockaddr_in dest;
  char buffer[MAXBUF + 1] = { 0 };
  SSL_CTX* ctx;
  SSL* ssl;

  SSL_library_init();
  OpenSSL_add_all_algorithms();
  SSL_load_error_strings();

  ctx = SSL_CTX_new(SSLv23_client_method());
  if (ctx == NULL)
  {
    WSACleanup();
    return 0;
  }

  WSADATA wsaData;

  WSAStartup(MAKEWORD(2, 2), &wsaData);
  if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
  {
    WSACleanup();
    return 0;
  }

  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  {
    WSACleanup();
    return 0;
  }

  dest.sin_family = AF_INET;
  dest.sin_addr.s_addr = inet_addr("127.0.0.1");
  dest.sin_port = htons(9999);

  if (connect(sockfd, (struct sockaddr*)&dest, sizeof(dest)) != 0)
  {
    WSACleanup();
    return 0;
  }

  ssl = SSL_new(ctx);
  SSL_set_fd(ssl, sockfd);

  if (SSL_connect(ssl) != -1)
  {
    printf("SSL 连接类型: %s \n", SSL_get_cipher(ssl));
  }

  // 发送文件
  UploadFile(ssl, "d://lyshark.exe");

finish:
  SSL_shutdown(ssl);
  SSL_free(ssl);
  closesocket(sockfd);
  SSL_CTX_free(ctx);

  system("pause");
  return 0;
}

读者可自行编译这段代码,并首先启动服务端等待传输,接着打开客户端,此时客户端中的d://lyshark.exe将被传输到服务端的特定目录下,如下图所示;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Excel 转 Json 、Node.js实现(应用场景:i18n国际化)

创作灵感来源于在线转换是按照换行符去转换excel内容换行符后很难处理 本文是按单元格转换 const xlsx require(node-xlsx) const fs require(fs) const xlsxData xlsx.parse(./demo.xlsx) // 需要转换的excel文件// 数据处理 方便粘贴复制 const data xlsxData[2].data …

Hello Vue!

目录 前言 hello vue 为什么要new Vue(),而不能直接调用Vue()? Vue构造函数中的形参options template配置项 $mount()方法 前言 从此篇博客开始&#xff0c;将开启vue的学习&#xff0c;查缺补漏。 只要学计算机语言&#xff0c;那么hello xxx那一定是入门第一行代码了…

CSS 链接、列表、表格、盒子模型

一、CSS链接: 不同的链接可以由不同的样式。链接的样式可以用任何CSS属性&#xff08;比如颜色、字体、背景等&#xff09;。 链接的四种状态&#xff1a; a.link&#xff1a;正常&#xff0c;未访问过的链接&#xff1b; a.visited&#xff1a;用户已访问过的链接&#xf…

什么是CE认证?蓝牙耳机出口欧盟CE认证如何办理?CE-RED认证办理

蓝牙耳机是一种基于蓝牙技术的一种小型设备&#xff0c;只需要把这种轻巧的设备藏在耳机边而不需要直接使用通讯设备&#xff08;手机、电脑等&#xff09;就可以实现自由通话。蓝牙耳机就是将蓝牙技术应用在免持耳机上&#xff0c;让使用者可以免除恼人电线的牵绊&#xff0c;…

C++:类和对象(下)

1.再谈构造函数&#xff1a; 构造函数体赋值&#xff1a; 回顾&#xff1a;在创建对象时&#xff0c;编译器通过调用构造函数&#xff0c;给对象中各个成员变量一个合适的初始值。 class Date { public:Date(int year, int month, int day){_year year;_month month;_day d…

如何避免JavaScript中的内存泄漏?

前言 过去&#xff0c;我们浏览静态网站时无须过多关注内存管理&#xff0c;因为加载新页面时&#xff0c;之前的页面信息会从内存中删除。 然而&#xff0c;随着单页Web应用&#xff08;SPA&#xff09;的兴起&#xff0c;应用程序消耗的内存越来越多&#xff0c;这不仅会降低…

iOS加固原理与常见措施:保护移动应用程序安全的利器

目录 iOS加固原理与常见措施&#xff1a;保护移动应用程序安全的利器 前言 一、iOS加固的原理 1. 代码混淆 2. 加密算法 3. 防调试技术 4. 签名校验 二、iOS加固的常见措施 1. 代码混淆 2. 加密算法 3. 防调试技术 4. 签名校验 三、iOS加固的效果和注意事项 参考…

网络原理---拿捏传输层:TCP/UDP协议

文章目录 UDP协议源端口、目的端口UDP长度校验和 TCP协议源端口、目的端口4位首部长度、选项保留位&#xff1a;6位6个特殊标志位32位序号、32位确认序号&#xff1a;在确认应答机制中使用16位窗口大小&#xff1a;在流量控制机制中使用16位校验和 TCP协议 VS UDP协议 在本篇中…

Web时代下,软件系统的持续进步,是否能完全替代人力节省成本?

Web时代下&#xff0c;软件系统的持续进步&#xff0c;是否能完全替代人力节省成本&#xff1f; 随着全球经济的蓬勃发展&#xff0c;众多经济学家纷纷提出了新的管理理念&#xff0c;例如在20世纪50年代&#xff0c;西蒙提出管理依赖信息和决策的思想&#xff0c;但在同时期的…

20231107-前端学习炫酷菜单效果和折叠侧边栏

炫酷菜单效果 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>炫酷菜单效果</title><…

消息中间件简介

一、 分布式系统消息通信技术简介 分布式系统消息通信技术主要包括以下几种&#xff1a; 1. RPC(Remote Procedure Call Protocol). 一般是C/S方式&#xff0c;同步的&#xff0c;跨语言跨平台&#xff0c;面向过程 2. CORBA(Common Object Request Broker Architecture). CO…

搜索引擎Elasticsearch基础与实践

倒排索引 将文档中的内容分词&#xff0c;然后形成词条。记录每条词条与数据的唯一表示如id的对应关系&#xff0c;形成的产物就是倒排索引&#xff0c;如下图&#xff1a; ElasticSearch数据的存储和搜索原理 这里的索引库相当于mysql中的database。一个文档&#xff08;do…

【基带开发】AD9361通信基础:复数乘法 除法

复数 是实数和虚数的组合 例子&#xff1a;3.6 4i, −0.02 1.2i, 25 − 0.3i, 0 2i 乘法 除法

在maven官网中如何下载低版本的maven

链接&#xff1a;https://archive.apache.org/dist/maven/maven-3/

vscode设置pycharm中的项目路径和debug方法

真大佬在这 真大佬在这 必须给大佬star 命令行运行&#xff1a; export PYTHONPATH:pwd:/home/bennie/bennie/bennie_project/AI_Lab python main.py 当关闭此命令行时&#xff0c;临时路径会清除&#xff0c;可以将上述export的整条语句&#xff0c;加入~/.bashrc中 该命令中…

JDBC SQL Server Source Connector: 一览与实践

在快速发展的数据驱动业务环境中&#xff0c;确保数据在各个系统间高效、准确地同步至关重要。为了进一步的数据处理和分析&#xff0c;经常需要将这些数据同步到其他数据处理系统。Apache SeaTunnel 提供了一个强大而灵活的数据集成框架&#xff0c;使得从 SQL Server 到其他系…

「随笔」浅谈2023年云计算的发展趋势

在2023年&#xff0c;云计算的发展趋势将受到政治、经济、社会和科技四个维度的影响。以下是对这些维度的具体分析&#xff1a; 1.1 政治维度&#xff1a; 全球政策推动&#xff1a; 随着全球各国政策对云计算的重视程度不断提高&#xff0c;云计算服务将获得更广泛的市场准入…

MES管理系统中常规的生产建模有哪些

随着制造业的快速发展&#xff0c;MES生产管理系统已经成为了现代制造业不可或缺的核心系统。MES通过对生产过程进行建模&#xff0c;实现了生产过程的可视化、可控制和可优化&#xff0c;为企业提供了全方位的生产管理解决方案。本文将深化对MES管理系统及其主要生产模型的理解…

『MySQL快速上手』-⑥-表的约束

文章目录 1.空属性2.默认值3.列描述4.zerofill5.主键6.自增长7.唯一键8.外键9.综合案例 真正约束字段的是数据类型&#xff0c;但是数据类型约束很单一&#xff0c;需要有一些额外的约束&#xff0c;更好的保证数据的合法性&#xff0c;从业务逻辑角度保证数据的正确性。 1.空…

第一个ARM程序裸板点灯

硬件知识LED原理图 如何点亮一个LED灯&#xff1f; 看原理图&#xff0c;确定控制LED的引脚。看主芯片的芯片手册&#xff0c;确定如何设置控制这个引脚。写程序。 LED有插脚封装的、贴片封装的。 它们长得完全不一样&#xff0c;因此我们在原理图中把它们抽象出来。 点亮…