01. rsa 操作
windows简单安装openssl:http://slproweb.com/products/Win32OpenSSL.html
Win32OpenSSL-1_1_1c.zip
rsa需要openssl库函数,直接安装这个程序(下一步下一步不需要自己改动)即可
安装完查看版本:

#define _CRT_SECURE_NO_WARNINGS#include <iostream>#include <windows.h>#include <openssl\rsa.h>#include <openssl\pem.h>#include <openssl\rand.h>#include <openssl\applink.c>#pragma comment(lib, "libcrypto.lib")#define PUB_KEY_FILE "pubkey.pem" // 公钥路径#define PRI_KEY_FILE "prikey.pem" // 私钥路径// 函数方法生成密钥对void generate_rsa_key(){// 生成 rsa 密钥对, 参数一密钥长度,参数二公钥指数 e,参数三四可以不指定RSA* keypair = RSA_generate_key(1024, RSA_F4, NULL, NULL);// 从生成的密钥对中读取私钥到内存对象BIO* pri = BIO_new(BIO_s_mem());PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);// 获取密钥长度并且申请空间进行保存size_t pri_len = BIO_pending(pri);char* pri_key = (char*)calloc(pri_len + 1, sizeof(char));BIO_read(pri, pri_key, pri_len);// 将生成的私钥写入到指定的文件中FILE* private_file = nullptr;if (fopen_s(&private_file, PRI_KEY_FILE, "w") == NULL){if (pri_key && private_file){fputs(pri_key, private_file);fclose(private_file);}}BIO* pub = BIO_new(BIO_s_mem());PEM_write_bio_RSAPublicKey(pub, keypair);size_t pub_len = BIO_pending(pub);char* pub_key = (char*)calloc(pub_len + 1, sizeof(char));BIO_read(pub, pub_key, pub_len);FILE* public_file = nullptr;if (fopen_s(&public_file, PUB_KEY_FILE, "w") == NULL){if (pub_key && public_file){fputs(pub_key, public_file);fclose(public_file);}}// 释放对应的资源,防止泄露RSA_free(keypair);BIO_free_all(pub);BIO_free_all(pri);free(pri_key);free(pub_key);}/*加密最大长度为加密长度-41*/RSA* get_public_key(){// 打开公钥文件FILE* public_file = nullptr;if (fopen_s(&public_file, PUB_KEY_FILE, "r") == NULL){// 从指定文件中读取公钥RSA* rsa = PEM_read_RSAPublicKey(public_file, NULL, NULL, NULL);if (public_file) fclose(public_file);return rsa;}return nullptr;}RSA* get_private_key(){// 打开私钥文件FILE* private_file = nullptr;if (fopen_s(&private_file, PRI_KEY_FILE, "r") == NULL){// 从指定文件中读取公钥RSA* rsa = PEM_read_RSAPrivateKey(private_file, NULL, NULL, NULL);if (private_file) fclose(private_file);return rsa;}return nullptr;}BYTE* rsa_encrypt(BYTE* data, int data_len, RSA* rsa){int rsa_len = RSA_size(rsa);BYTE* encrypt = (BYTE*)malloc(rsa_len);// RSA 1024 加密的明文分组长度不能超过 117, 生成的密文长度是 128// 且 RSA 1024 不支持分组加密,意味着只能自己使用循环进行加密。if (data_len > 117) return nullptr;// RSA_PKCS1_PADDING 填充方式,随机添加一些数据进行加密和解密RSA_public_encrypt(data_len, data, encrypt, rsa, RSA_PKCS1_PADDING);return encrypt;}// 解密数据,BYTE* rsa_decrypt(BYTE* data, RSA* rsa){int rsa_len = RSA_size(rsa);BYTE* decrypt = (BYTE*)malloc(rsa_len);RSA_private_decrypt(rsa_len, data, decrypt, rsa, RSA_PKCS1_PADDING);return decrypt;}int main(){// 生成 rsa 密钥对并读取到 rsa 对象中generate_rsa_key();RSA* public_key = get_public_key();RSA* private_key = get_private_key();// 构建需要加密的文件BYTE plaintext[117] = { 0 };memset(plaintext, 'a', 117);// 加密和解密BYTE* encrypt = rsa_encrypt(plaintext, 117, public_key);BYTE* decrypt = rsa_decrypt(encrypt, private_key);return 0;}
02. tcp 客户端
#include <iostream>#include <ws2tcpip.h>// 0. 进行套接字编程必须用到的头文件和库#include <winsock2.h>#pragma comment(lib,"ws2_32.lib")#define CLIENT_COUNT 100// 根据传入的布尔值进行相应的输出void check_result(bool b, LPCSTR msg){// 参数一因该是一个表达式,如果表达式为 true 就输出if (b){printf("error: %s\n", msg);ExitProcess(0);}}// 创建一个客户端进行连接DWORD CALLBACK create_client(LPVOID param){// 创建套接字[IP:PORT],选择服务商(联通? 电信? 移动)// - AF_INET: 表示使用网络传输协议// - SOCK_STREAM: 表示使用流式套接字(TCP)// - IPPROTO_TCP 表示 TCP, IPPROTO_UDP 表示 UDPSOCKET client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);check_result(client == INVALID_SOCKET, "socket()");// 作为客户端来讲,每一个客户端套接字都会默认的分配端口// 连接到服务器,打电话(需要知道打给谁)sockaddr_in serveraddr = { AF_INET };serveraddr.sin_port = htons(0x1234);inet_pton(AF_INET, "127.0.0.1", &serveraddr.sin_addr);int result = connect(client, (sockaddr*)&serveraddr, sizeof(serveraddr));check_result(result == SOCKET_ERROR, "accept()");// 收发消息 send\recv,打电话while (true){// 发送当前是第几个客户端到服务器send(client, (char*)¶m, 4, 0);Sleep(500);}}int main(){// 初始化网络环境,搜索信号(3G? 4G?)WSAData wsadata = { 0 };int result = WSAStartup(0x0202, &wsadata);check_result(result != 0 || wsadata.wVersion != 0x0202, "WSAStartup()");// 创建指定个数的 客户端for (int i = 0; i < CLIENT_COUNT; ++i)CreateThread(NULL, 0, create_client, (LPVOID)i, 0, NULL);// WaitForMultipleObjects 能够等待的句柄最多 64 个system("pause");// 清理网络环境,销户WSACleanup();return 0;}
03. tcp 服务端
// TCP 是什么? 传输层的协议,主要用于数据的传输。TCP 是// 相对安全的,面向有连接的。确保数据的完整性。类似于打电// 话,会有 响铃 + 接通 + 交流 的过程。// UDP 是什么? 传输层的协议,主要用于数据的传输。UDP 是// 相对不稳定的,面向无连接的。类似于 BB 机,只会将消息发// 送出去,并不能保证消息一定会被接收到。// 如何确保消息发送给当前局域网内的某一个机器? 当计算机连// 接到网络中后,路由器会分配一个唯一的 ip 地址给具体的机,// 器,当信息传递给路由器的时候,会根据相应的 ip 地址传递给// 对应的设备。// 如何确保消息发送给当前系统的某一个程序? 每一个独立套接字// 都会拥有独一无二的端口,当系统接受到网络信息之后,会根据对// 应的端口将信息发送给指定的程序。// ip 和 端口 的组成是什么? ipv4 的地址实际上是一个四字节的// 整数数据,组成通常 x.x.x.x 的形式,假设存在 1.1.1.127 这个// ip 对应的四字节实际上是 0x0101017F。端口在计算机中通常有// 65535 个,实际可以由一个 WORD 来保存。// 数据在网络传输的过程中是如何存储的? 通常在个人计算机中,数据// 都是以小端方式存储的,在网络数据的传输过程中,规定应该使用大端// 的方式保存所有的数据。#include <iostream>#include <ws2tcpip.h>// 0. 进行套接字编程必须用到的头文件和库#include <winsock2.h>#pragma comment(lib,"ws2_32.lib")// 根据传入的布尔值进行相应的输出void check_result(bool b, LPCSTR msg){// 参数一因该是一个表达式,如果表达式为 true 就输出if (b){printf("error: %s\n", msg);ExitProcess(0);}}// 创建一个互斥体,用于互斥输出HANDLE Mutex = CreateMutex(NULL, FALSE, NULL);// 专门用于接受指定套接字的数据DWORD CALLBACK RecvThread(LPVOID param){// 从参数获取到套接字SOCKET client = (SOCKET)param;INT number = { 0 };// 循环接受套接字传入的数据,recv 的返回值应该是接受// 到的数据长度,如果返回值 <= 0 就表示断开了连接while (recv(client, (char*)&number, 4, 0) > 0){WaitForSingleObject(Mutex, INFINITE);printf("[%08X]: %d\n", GetCurrentThreadId(), number);ReleaseMutex(Mutex);}return 0;}int main(){// 1. 初始化网络环境,搜索信号(3G? 4G?)WSAData wsadata = { 0 };int result = WSAStartup(0x0202, &wsadata);check_result(result != 0 || wsadata.wVersion != 0x0202, "WSAStartup()");// 2. 创建套接字[IP:PORT],选择服务商(联通? 电信? 移动)// - AF_INET: 表示使用网络传输协议// - SOCK_STREAM: 表示使用流式套接字(TCP)// - IPPROTO_TCP 表示 TCP, IPPROTO_UDP 表示 UDPSOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);check_result(server == INVALID_SOCKET, "socket()");// 3. 绑定套接字到对应的 ip:port,类似于选择手机号sockaddr_in serveraddr = { AF_INET };serveraddr.sin_port = htons(0x1234);// - 127.0.0.1 在大多数设备上指向的都是当前的主机inet_pton(AF_INET, "127.0.0.1", &serveraddr.sin_addr);result = bind(server, (sockaddr*)&serveraddr, sizeof(serveraddr));check_result(result == SOCKET_ERROR, "bind()");// 4. 开启监听模式,设置监听的最大数量,把卡装到手机开机result = listen(server, SOMAXCONN);check_result(result == SOCKET_ERROR, "listen()");// 编写一个死循环,在循环内不断的接收客户端while (true){// 5. 等待客户端的连接,接电话// - 等待哪一个套接字的连接、连接客户端的地址信息,结构体大小sockaddr_in clientaddr = { 0 };int length = sizeof(clientaddr);SOCKET client = accept(server, (sockaddr*)&clientaddr, &length);check_result(client == INVALID_SOCKET, "accept()");// 6. 为[每一个客户端]创建[单独]的线程,进行消息的接收 recv// - 如果没有创建线程,那么程序就会阻塞在 recv 函数,导致无法接受CreateThread(NULL, 0, RecvThread, (LPVOID)client, 0, NULL);}// 7. 关闭套接字,挂断电话closesocket(server);// 8. 清理网络环境,销户WSACleanup();system("pause");return 0;}
04. iocp 服务端
#include <iostream>#include <ws2tcpip.h>// 0. 进行套接字编程必须用到的头文件和库#include <winsock2.h>#pragma comment(lib,"ws2_32.lib")// 用于保存异步信息的结构体struct MYOVERLAPPED{OVERLAPPED overlapped;WSABUF wsabuf;};// 根据传入的布尔值进行相应的输出void check_result(bool b, LPCSTR msg){// 参数一因该是一个表达式,如果表达式为 true 就输出if (b){printf("error: %s\n", msg);ExitProcess(0);}}// 创建一个互斥体,用于互斥输出HANDLE Mutex = CreateMutex(NULL, FALSE, NULL);// 专门用于接受指定套接字的数据DWORD CALLBACK RecvThread(LPVOID param){// 首先获取到参数传入的 iocp 对象HANDLE iocp = (HANDLE)param;DWORD read = 0;ULONG_PTR completion_key = NULL;MYOVERLAPPED* overlapped = nullptr;// 不断的接受队列中传入的消息while (true){// 从完成端口队列获取信息BOOL result = GetQueuedCompletionStatus(iocp, // 从哪一个 iocp 获取&read, // 实际接收的数量&completion_key, // 在这里是产生消息的套接字// 接收的 OVERLAPPED** ,但实际刚才传入的是 OVERLAPPED*(LPOVERLAPPED*)&overlapped, // 重叠IO结构INFINITE); // 等待时长// 如果消息接收成功就输出if (result == TRUE && read > 0){WaitForSingleObject(Mutex, INFINITE);printf("[%08X]: %d\n", GetCurrentThreadId(),*(int*)overlapped->wsabuf.buf);ReleaseMutex(Mutex);// 需要再次投递一个请求DWORD flags = 0;WSARecv((SOCKET)completion_key, // 接受谁的信息&overlapped->wsabuf, // 消息保存到哪里1, // wsabuf 结构的数量NULL, // 对于异步IO,可以填写0&flags, // 对应 recv 的最后一个参数(LPWSAOVERLAPPED)overlapped,// 重叠 IO 结构体NULL); // 回调函数}}return 0;}int main(){// [1]. IOCP 是用有限的线程处理多个异步操作,线程数量通常是CPU核心 * 2SYSTEM_INFO system_info = { 0 };GetSystemInfo(&system_info);// [2]. 创建一个 IOCP 对象,维护所有的线程HANDLE iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);// [3]. 根据获取到的核心数量,创建 iocp 工作线程,传入 iocp 对象for (DWORD i = 0; i < system_info.dwNumberOfProcessors * 2; ++i)CreateThread(NULL, 0, RecvThread, (LPVOID)iocp, 0, NULL);// 1. 初始化网络环境,搜索信号(3G? 4G?)WSAData wsadata = { 0 };int result = WSAStartup(0x0202, &wsadata);check_result(result != 0 || wsadata.wVersion != 0x0202, "WSAStartup()");// 2. 创建套接字[IP:PORT],选择服务商(联通? 电信? 移动)// - AF_INET: 表示使用网络传输协议// - SOCK_STREAM: 表示使用流式套接字(TCP)// - IPPROTO_TCP 表示 TCP, IPPROTO_UDP 表示 UDPSOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);check_result(server == INVALID_SOCKET, "socket()");// 3. 绑定套接字到对应的 ip:port,类似于选择手机号sockaddr_in serveraddr = { AF_INET };serveraddr.sin_port = htons(0x1234);// - 127.0.0.1 在大多数设备上指向的都是当前的主机inet_pton(AF_INET, "127.0.0.1", &serveraddr.sin_addr);result = bind(server, (sockaddr*)&serveraddr, sizeof(serveraddr));check_result(result == SOCKET_ERROR, "bind()");// 4. 开启监听模式,设置监听的最大数量,把卡装到手机开机result = listen(server, SOMAXCONN);check_result(result == SOCKET_ERROR, "listen()");// 编写一个死循环,在循环内不断的接收客户端while (true){// 5. 等待客户端的连接,接电话// - 等待哪一个套接字的连接、连接客户端的地址信息,结构体大小sockaddr_in clientaddr = { 0 };int length = sizeof(clientaddr);SOCKET client = accept(server, (sockaddr*)&clientaddr, &length);check_result(client == INVALID_SOCKET, "accept()");// [4]. 将每一个接收到的套接字都绑定到 iocp 上// - 参数三:完成键,通常用于保存产生消息的句柄(客户端句柄)CreateIoCompletionPort((HANDLE)client, iocp, client, 0);// WSARecv 对需要使用单独的 MYOVERLAPPED 结构体。MYOVERLAPPED* overlapped = new MYOVERLAPPED{ 0 };overlapped->wsabuf.len = 0x10;overlapped->wsabuf.buf = new CHAR[0x10]{ 0 };// [5]. 投递一个接收客户端数据的请求,使用 WSARecv,对于每一个DWORD flags = 0;WSARecv(client, // 接受谁的信息&overlapped->wsabuf, // 消息保存到哪里1, // wsabuf 结构的数量NULL, // 对于异步IO,可以填写0&flags, // 对应 recv 的最后一个参数(LPWSAOVERLAPPED)overlapped,// 重叠 IO 结构体NULL); // 回调函数// 将请求投递到 IOCP 的队列中,一旦请求执行完毕,GetQueuedCompletionStatus// 就会从完成请求的队列中获取到这个投递的请求,在这个地方,主线程会被切换到工// 作线程,执行 GetQueuedCompletionStatus,错误的真正地址是在这里。}// 7. 关闭套接字,挂断电话closesocket(server);// 8. 清理网络环境,销户WSACleanup();system("pause");return 0;}// 使用 IOCP 的步骤: 主线程// 1. 创建一个 iocp 对象// 2. 根据 cpu 核心数量创建线程// 3. 接收客户端,将接收的客户端绑定到 iocp,即添加到对象队列中// 4. 投递一个 IO 请求,WSARecv 请求,即接收目标的信息// 每一个请求都应该对应有不同的 OVERLAPPED 结构体,且应该在堆空间// 使用 IOCP 的步骤: 工作线程// 1. GetQueuedCompletionStatus 从完成队列中取出消息// 2. 函数如果返回 FALSE 或者实际操作的字节 <=0 就失败// 3. 可以从 OVERLAPPED 中获取到想要的信息并输出// 4. 为了能够继续的获取下一次信息,需要再次投递请求
05. tcp 文件发送
#define _CRT_SECURE_NO_WARNINGS#include <iostream>#include <ws2tcpip.h>// 0. 进行套接字编程必须用到的头文件和库#include <winsock2.h>#pragma comment(lib,"ws2_32.lib")// windows 中检查了一些重复包含#include <windows.h>#include "function.h"#define SECTION_SIZE 10240// 发送文件的时候分成两个步骤:1 发送文件的请求头(基本信息)typedef struct _FILE_HEADER{CHAR filename[MAX_PATH] = { 0 }; // 文件的名称SIZE_T filesize = 0; // 文件的大小DWORD section_count = 0; // 接收整个文件需要的次数CHAR sig[128] = { 0 }; // 签名} FILE_HEADER, *PFILE_HEADER;// 发送文件的时候分成两个步骤:2 发送文件的请求体(n个,第几个区块,以及内容)typedef struct _FILE_SECTION{int index = 0; // 文件的大小DWORD size = 0; // 一次发送的大小CHAR data[SECTION_SIZE] = { 0 }; // 发送的具体数据} FILE_SECTION, * PFILE_SECTION;// 根据传入的布尔值进行相应的输出void check_result(bool b, LPCSTR msg){// 参数一因该是一个表达式,如果表达式为 true 就输出if (b){printf("error: %s\n", msg);ExitProcess(0);}}int main(){// 1. 初始化网络环境,搜索信号(3G? 4G?)WSAData wsadata = { 0 };int result = WSAStartup(0x0202, &wsadata);check_result(result != 0 || wsadata.wVersion != 0x0202, "WSAStartup()");// 2. 创建套接字[IP:PORT],选择服务商(联通? 电信? 移动)// - AF_INET: 表示使用网络传输协议// - SOCK_STREAM: 表示使用流式套接字(TCP)// - IPPROTO_TCP 表示 TCP, IPPROTO_UDP 表示 UDPSOCKET sender = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);check_result(sender == INVALID_SOCKET, "socket()");// 3. 绑定套接字到对应的 ip:port,类似于选择手机号sockaddr_in serveraddr = { AF_INET };serveraddr.sin_port = htons(0x1234);// - 127.0.0.1 在大多数设备上指向的都是当前的主机inet_pton(AF_INET, "127.0.0.1", &serveraddr.sin_addr);result = bind(sender, (sockaddr*)&serveraddr, sizeof(serveraddr));check_result(result == SOCKET_ERROR, "bind()");// 4. 开启监听模式,设置监听的最大数量,把卡装到手机开机result = listen(sender, SOMAXCONN);check_result(result == SOCKET_ERROR, "listen()");// 5. 等待客户端的连接,接电话// - 等待哪一个套接字的连接、连接客户端的地址信息,结构体大小sockaddr_in clientaddr = { 0 };int length = sizeof(clientaddr);SOCKET reciver = accept(sender, (sockaddr*)&clientaddr, &length);check_result(reciver == INVALID_SOCKET, "accept()");// 6. 打开需要发送的文件,获取相关的信息填充到结构体中HANDLE file = CreateFileA("demo.exe", GENERIC_READ, FILE_SHARE_READ,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);check_result(file == INVALID_HANDLE_VALUE, "CreateFileA()");SIZE_T filesize = GetFileSize(file, NULL);DWORD sectioncount = filesize % SECTION_SIZE == 0 ?filesize / SECTION_SIZE : (filesize / SECTION_SIZE) + 1;FILE_HEADER file_header = { "demo.exe", filesize, sectioncount };calc_file_sig("demo.exe", file_header.sig);send(reciver, (CHAR*)&file_header, sizeof(file_header), 0);// 7. 根据计算出的区块数量,循环发送每一个区块for (DWORD i = 0; i < sectioncount; ++i){// 7.1 创建缓冲区用于保存需要发送的区块FILE_SECTION section = { i };// 7.2 修改文件指针指向每一个区块的首地址SetFilePointer(file, i * SECTION_SIZE, 0, FILE_BEGIN);// 7.3 从指定的位置读取数据保存并发送ReadFile(file, section.data, SECTION_SIZE, §ion.size, NULL);//printf("%d:%d\n", i, section.size);send(reciver, (CHAR*)§ion, sizeof(section), 0);}// bug 产生的原因是过早的关闭了服务器(发送端)的套接字,如果已经关闭了// 但是客户端还没有接收完数据,就会直接导致丢包CloseHandle(file);system("pause");return 0;}
06. tcp 文件接收
#define _CRT_SECURE_NO_WARNINGS#include <iostream>#include <ws2tcpip.h>// 0. 进行套接字编程必须用到的头文件和库#include <winsock2.h>#pragma comment(lib,"ws2_32.lib")#include <windows.h>#include "function.h"#define SECTION_SIZE 10240// 发送文件的时候分成两个步骤:1 发送文件的请求头(基本信息)typedef struct _FILE_HEADER{CHAR filename[MAX_PATH] = { 0 }; // 文件的名称SIZE_T filesize = 0; // 文件的大小DWORD section_count = 0; // 接收整个文件需要的次数CHAR sig[128] = { 0 }; // 签名} FILE_HEADER, * PFILE_HEADER;// 发送文件的时候分成两个步骤:2 发送文件的请求体(n个,第几个区块,以及内容)typedef struct _FILE_SECTION{int index = 0; // 文件的大小DWORD size = 0; // 一次发送的大小CHAR data[SECTION_SIZE] = { 0 }; // 发送的具体数据} FILE_SECTION, * PFILE_SECTION;// 根据传入的布尔值进行相应的输出void check_result(bool b, LPCSTR msg){// 参数一因该是一个表达式,如果表达式为 true 就输出if (b){printf("error: %s\n", msg);ExitProcess(0);}}int main(){// 初始化网络环境,搜索信号(3G? 4G?)WSAData wsadata = { 0 };int result = WSAStartup(0x0202, &wsadata);check_result(result != 0 || wsadata.wVersion != 0x0202, "WSAStartup()");// 创建套接字[IP:PORT],选择服务商(联通? 电信? 移动)// - AF_INET: 表示使用网络传输协议// - SOCK_STREAM: 表示使用流式套接字(TCP)// - IPPROTO_TCP 表示 TCP, IPPROTO_UDP 表示 UDPSOCKET reciver = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);check_result(reciver == INVALID_SOCKET, "socket()");// 作为客户端来讲,每一个客户端套接字都会默认的分配端口// 连接到服务器,打电话(需要知道打给谁)sockaddr_in serveraddr = { AF_INET };serveraddr.sin_port = htons(0x1234);inet_pton(AF_INET, "127.0.0.1", &serveraddr.sin_addr);result = connect(reciver, (sockaddr*)&serveraddr, sizeof(serveraddr));check_result(result == SOCKET_ERROR, "accept()");// 直接接收服务器发送过来的文件头信息FILE_HEADER file_header = { 0 };recv(reciver, (CHAR*)&file_header, sizeof(file_header), 0);// 使用接收到的名称创建文件HANDLE file = CreateFileA("demo1.exe", GENERIC_WRITE, NULL,NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);check_result(file == INVALID_HANDLE_VALUE, "CreateFileA()");// 根据接收到的轮数,循环接收整个文件for (DWORD i = 0; i < file_header.section_count; ++i){// 7.1 创建缓冲区用于接收块的信息FILE_SECTION section = { 0 };int n = recv(reciver, (CHAR*)§ion, sizeof(section), 0);// 7.2 修改文件指针指向接收到的数据对应文职SetFilePointer(file, section.index * SECTION_SIZE, 0, FILE_BEGIN);// 7.3 将数据写到指定的位置DWORD aaa;if (section.size == 0)break;//printf("%d:%d\n", section.index, section.size);WriteFile(file, section.data, section.size, &aaa, NULL);}CloseHandle(file);if (verify_file_sig("demo1.exe", file_header.sig))printf("签名校验失败\n");elseprintf("签名校验成功\n");system("pause");// 清理网络环境,销户WSACleanup();return 0;}
