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将被传输到服务端的特定目录下,如下图所示;

20.8 OpenSSL 套接字SSL传输文件的更多相关文章
- Python之路(第三十二篇) 网络编程:udp套接字、简单文件传输
一.UDP套接字 服务端 # udp是无链接的,先启动哪一端都不会报错 # udp没有链接,与tcp相比没有链接循环,只有通讯循环 server = socket.socket(socket.AF_I ...
- 4月20日 python学习总结 套接字工作流程
一.套接字工作流程 一个生活中的场景.你要打电话给一个朋友,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了.等交流结束,挂断电话结束此次交谈. 生活中的场景就解释了这 ...
- 5-8套接字socket
socket概念 socket层 理解socket Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协 ...
- python 全栈开发,Day33(tcp协议和udp协议,互联网协议与osi模型,socket概念,套接字(socket)初使用)
先来回顾一下昨天的内容 网络编程开发架构 B/S C/S架构网卡 mac地址网段 ip地址 : 表示了一台电脑在网络中的位置 子网掩码 : ip和子网掩码按位与得到网段 网关ip : 内置在路由器中的 ...
- 网络编程(socket,套接字)
服务端地址不变 ip + mac 标识唯一一台机器 ip +端口 标识唯一客户端应用程序 套接字: 网络编程 网络编程 一.python提供了两个级别访问的网络服务 低级别的网络服务支持基本的 S ...
- day29 python 套接字socket TCP udp 形式发送信息的区别
我们经常把socket翻译为套接字,socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信. socket起源于UNIX,在 ...
- Python套接字
1.客户端/服务器架构 什么是客户端/服务器架构?对于不同的人来说,它意味着不同的东西,这取决于你问谁以及描述的是软件还是硬件系统.在这两种情况中的任何一种下,前提都很简单:服务器就是一系列硬件或软件 ...
- 《Unix网络编程卷1:套接字联网API》读书笔记
第一部分:简介和TCP/IP 第1章:简介 第2章:传输层:TCP.UDP和SCTP TCP:传输控制协议,复杂.可靠.面向连接协议 UDP:用户数据报协议,简单.不可靠.无连接协议 SCTP:流控制 ...
- python基础之try异常处理、socket套接字基础part1
异常处理 错误 程序里的错误一般分为两种: 1.语法错误,这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正 2.逻辑错误,人为造成的错误,如数据类型错误.调用方法错误等,这些解 ...
- 网络基础之网络协议篇---CS架构--网络通信--osi 协议---套接字socket--粘包
1 C\S 客户端/服务器架构: .硬件 C/S架构 (打印机) .软件 C/S 架构 互联网中处处是C/S架构 如黄色网站是服务端,你的浏览器是客户端(B/S架构也是C/S架构的一种) 腾讯作为服务 ...
随机推荐
- 使用nginx代理emqx的TCP、WS、WSS连接请求
项目代理关系: 注:主机上已存在名为:nginx-proxy 的一级 nginx 的代理,将监听了主机的 80.443端口 docker-compose.yml version: "3.7& ...
- 第五届蓝桥杯(2014)C/C++大学A组省赛题解
第一题.猜年龄 小明带两个妹妹参加元宵灯会.别人问她们多大了,她们调皮地说:"我们俩的年龄之积是年龄之和的6倍".小明又补充说:"她们可不是双胞胎,年龄差肯定也不超过8岁 ...
- 一道C语言改错题
下午,在上班,读者发来一道题目,问我怎么做.我大概瞄了一眼,看题目也不难.就先让他自己上网查下. 过了一会,他说查不到,问了群里,大家也不太会. 好吧,起码这位读者自己思考过,也问过了. 题目如下,找 ...
- 【Qt】开源一键代码开光神器,一行代码给你的项目施加祝福,减少Bug
年底啦,没什么项目,想摸鱼划水没见到什么好玩的东西,看到有人分享这个,直接做个库来玩下,之后说不定会嵌到公司的项目里面去.... 效果如下,佛光普照! 输入也只需要一行命令 magic_spells: ...
- 线性代数 · 矩阵 · Matlab | 满秩分解代码实现
背景 - 矩阵的满秩分解: 若 A 为 m×n 矩阵,rank(A) = r,则存在 F m×r.G r×n,使得 A = FG. 其中,F 列满秩,G 行满秩. 求满秩分解的方法: 得到 A 的行最 ...
- JMeter接口性能测试使用
下载完JMeter以后,通过JMeter.bat启动JMeter,打开JMeter界面如下所示: 右击"测试计划">添加>Threads(Users)>线程组.J ...
- 如何开发一套苹果cms前端模板
本文运用了苹果cms官网的模板开发教程,开发了一套苹果cms的前端模板,感兴趣的同学可以去github下载使用. 什么是模板 模板是网站的主题外观,也被称为主题或皮肤.通过使用不同的模板,网站的前台可 ...
- CSS : 使用 z-index 的前提
使用 z-index 前 , 需要将元素 定位设置为 position : relative .
- .NET技术面试题系列(2) -sql server数据库优化规范
1.数据库优化规范 a.索引 每个表格都要求建立主键,主键上不一定需要强制建立聚集索引. 聚集索引,表中存储的数据按照索引的顺序存储,即逻辑顺序决定了表中相应行的物理顺序,因此聚集索引的字段值应是不会 ...
- Oracle数据类型的简单学习之一
Oracle数据类型的简单学习之一 背景 因为信创安可替代的发展 有很多项目提到了数据库切换到国产数据库的要求. 一般情况是要求从Oracle/SQLServer 迁移到国产的: 达梦/瀚高/人大金仓 ...