c语言实现https客户端 源码+详细注释(OpenSSL下载,visual studio编译器环境配置)

OpenSSL的下载和环境配置

请参考:openssl下载安装教程
步骤:官网下载->安装到选定目录->配置环境变量->打开命令窗口检查是否安装成功
注意:
打开命令窗口(快捷键win+r,在弹出窗口内输入cmd按回车),输入命令openssl version如果显示openssl版本则表示安装成功。
我出现的问题:明明安装上了却显示

B:>openssl version
‘openssl’ 不是内部或外部命令,也不是可运行的程序
或批处理文件。

解决方法:更改到lib目录,输入命令:

B:\OpenSSL-Win64\lib>openssl.exe

因为我的版本openssl.exe文件在lib目录下,可以在OpenSSL-Win64文件夹里直接搜索openssl.exe,就知道在哪个目录下了。
运行之后再输入openssl version就会显示版本,例:

B:\OpenSSL-Win64\bin>openssl version
OpenSSL 3.1.0 14 Mar 2023 (Library: OpenSSL 3.1.0 14 Mar 2023)

出现版本信息代表安装成功。

visual studio项目环境配置

我使用visual studio2019版本,以下步骤仅供参考。
1.在属性页顶端右边,把平台改成x64(根据自己需要),点击右侧配置管理器按钮,将此项目的平台改成x64(根据自己需要)。
2.打开项目界面,在上方菜单栏选择项目->属性
3.在左侧选择VC++目录,选择包含目录,编辑,粘贴openssl的include目录的绝对路径。

例如:B:\OpenSSL-Win64\include

选择库目录,编辑,粘贴openssl的lib目录的绝对路径

例如:B:\OpenSSL-Win64\lib

4.选择左侧C/C++常规,选择附加包含目录,编辑,粘贴openssl的include目录的绝对路径。

例如:B:\OpenSSL-Win64\include

5.选择左侧链接器,选择下侧输入,选择右侧附加依赖项,编辑,写入libssl.lib,libcrypto.lib的路径。在lib目录中,打开自己下载的openssl文件夹看一下具体是哪个路径,不同版本可能不同,我使用的版本是 3.1.0 14

例如:
B:\OpenSSL-Win64\lib\libssl.lib
B:\OpenSSL-Win64\lib\libcrypto.lib

注意:编译器所有无法识别SSL…的问题都是环境没配置好,再仔细看一下上述步骤,都是一步步配置过的,亲测OK。

代码实现

思路

请添加图片描述

源码

#include<stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h> 
#include <openssl/ssl.h>
#pragma comment(lib, "Ws2_32.lib")
int main() {
	// 初始化 Winsock(windows套接字)
	/*WSADATA是windows API定义的一个结构,存储关于winsock实现的详细信息*/
	WSADATA wsaData;
	/*WSAStartup()这个函数用于初始化Winsock库,
	MAKEWORD(2, 2)相当于创建了一个对Winsock 2.2的版本请求,
	&wsaData用于将wsaData地址结构传入函数
	*/
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		/*
		WSAStartup返回了一个非0的值则代表初始化失败
		*/
		printf("WSAStartup failed\n");
		return 1;
	}
	printf("客户端Winsock初始化成功\n");
	printf("————————————————————\n");
	//创建客户端对象
	/*声明一个整型变量socket_fd用来存储套接字描述符
	*/
	int socket_fd;
	/*socket()函数用于创建一个新的套接字,
	AF_INET指定了地址族为ipv4,
	SOCK_STREAM指定了套接字类型为流式套接字,即TCP
	第三个参数,通常用来指定协议
	*/
	if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0))== 0){
		perror("socket failed");
		exit(EXIT_FAILURE);
	}
	/*声明一个结构体变量sock_addr,用于存储套接字地址信息(IPv4)
	*/
	struct sockaddr_in sock_addr;	
	sock_addr.sin_family = AF_INET; //使用ipv4地址族
	/*htons() 函数用于将主机字节顺序转换为网络字节顺序,确保在不同架构的计算机上,端口号的表示都是一致的。
	*/
	sock_addr.sin_port = htons(8080); //设置端口号为8080
	
	//设置网络ip
	/*调用inet_pton()函数将字符串形式的IP地址转换为网络字节序的二进制IP地址,
	并存储到sock_addr.sin_addr中
	*/
	if (inet_pton(AF_INET, "192.168.1.128", &sock_addr.sin_addr) <= 0) {
		/*inet_pton()函数返回值如果小于等于零,表示转换失败*/
		perror("inet_pton() failed");
		exit(EXIT_FAILURE);
	}
	printf("创建客户端对象成功,尝试连接服务器\n");
	printf("————————————————————\n");
	//连接服务器
	if ((connect(socket_fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) < 0)) {
		perror("connect failed\n");
		exit(EXIT_FAILURE);
	}
	printf("对服务器发起连接\n");

	//初始化openssl库

	//SSL库初始化
	SSL_library_init();
	//载入所有SSL算法
	SSLeay_add_ssl_algorithms();
	//载入所有SSL错误消息
	SSL_load_error_strings();
	//创建SSL会话环境
	//使用 TLS_client_method() 函数创建了一个 SSL 上下文结构(SSL_CTX)
	/*TLS_client_method()
	const SSL_METHOD *TLS_client_method(void);
	函数的返回值用于指定SSL/TSL连接使用的方法,这个方法指定了客户端如何与服务器端建立连接。
	通过调用该函数,获取一个用于SSL/TSL客户端的SSL_METHOD结构,这个结构被传递给SSL_CTX_new()函数,用于创建SSL_CTX上下文对象。
	  SSL_CTX_new()
	  SSL_CTX *SSL_CTX_new(const SSL_METHOD *method);
	  根据指定的SSL/TLS方法创建一个SSL/TSL上下文对象,该上下文对象包含了SSL/TSL连接的所有配置信息,包括加密算法、证书、私钥等。
	  若创建失败返回NULL。
	*/
	SSL_CTX* pctxSSL = SSL_CTX_new(TLS_client_method());
	if (pctxSSL == NULL) {
		printf("error ssl_ctx_new\n");
		return -1;
	}
	/*
	基于之前创建的 SSL 上下文(SSL_CTX),创建了一个 SSL 对象,该对象将使用指定的上下文对象来配置 SSL/TLS 连接
	*/
	SSL* psslSSL = SSL_new(pctxSSL);
	if (psslSSL == NULL) {
		printf("error ssl_new\n");
	}
	/*SSL_set_fd()函数用于将一个套接字文件描述符与SSL对象关联起来,从而使SSL对象可以在该套接字上进行SSL/TSL加密通信。
	*/
	SSL_set_fd(psslSSL, socket_fd);
	//使用之前创建的 SSL 结构(SSL),建立了 SSL 连接。
	/*SSL_connect()函数尝试与远程服务器建立安全连接。iErrorConnect表示连接的状态,如果连接失败返回值小于零。
	*/
	INT iErrorConnect = SSL_connect(psslSSL);
	if (iErrorConnect < 0) {
		//打印错误码
		printf("error SSL_connect,iErrorConnect=%d\n", iErrorConnect);
		//打印当前SSL连接所使用的加密算法
		/*SSL_get_cipher() 函数返回一个指向当前 SSL 连接所使用的加密算法字符串的指针。
		*/
	}
	/*SSL_get_cipher() 函数返回一个指向当前 SSL 连接所使用的加密算法字符串的指针。
	*/
	printf("SSL connection using:%s\n", SSL_get_cipher(psslSSL));

	//准备http请求
	char http[] = "GET /index.html HTTP/1.1\r\nHost: 192.168.10.124:8080\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nUpgrade-Insecure-Requests: 1\r\nMozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36\r\ntext/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\nAccept-Encoding: gzip, deflate\r\nAccept-Language: zh-CN,zh;q=0.9\r\n\r\n";
	
	
	//通过SSL连接发送http get请求,发送成功则返回发送的字节数,否则返回一个负值表示发送失败
	/*SSL_write()函数用于在SSL连接上写入数据,将http中的数据写入到与psslSSL相关的SSL连接中
	* 返回值小于零表示写入失败
	*/
	INT iErroeWrite = SSL_write(psslSSL,http,strlen(http));
	if (iErroeWrite<0) {
		printf("error SSL_write\n");
		return -1;
	}

	char buf[2048] = {0};
	/*
	
	*/
	INT iLength = 1;
	/*调用SSL_read函数从SSL连接中读取数据
	第一个参数:SSL连接对象
	第二个参数:指向接收缓冲区的指针
	第三个参数:缓冲区的大小
	函数返回读取到的字节数
	*/
	while ((iLength=SSL_read(psslSSL,buf, sizeof(buf)))>=1) {
	}
		
	printf("读取数据成功\n");
	printf("服务器端给出的回应是%s\n", buf);
	//关闭SSL连接
	SSL_shutdown(psslSSL);
	//释放SSL数据结构
	SSL_free(psslSSL);
	//释放SSL_CTX数据结构
	SSL_CTX_free(pctxSSL);
	//关闭套接字
	closesocket(socket_fd);
	WSACleanup();
	return 0;
}

参考链接

1.c语言https实现客户端
2.visual studio openssl环境配置
3.https协议详解

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

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

相关文章

leetcode代码记录(长度最小的子数组

目录 1. 题目&#xff1a;2. 我的代码&#xff1a;小结&#xff1a; 1. 题目&#xff1a; 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 连续 子数组 [numsl, numsl1, …, numsr-1, numsr] &#xff0c;并返回其…

外贸业务员如何说服老板拿到更低价

小伙伴问我说如何说服老板给到更好的价格&#xff0c;这个问题呢我在这里说一下我的观点 第一你需要去分析这个客户到底值不值得我们去给他花更多的一些心思&#xff0c;因为客户想要的这个价格既然已经突破了公司的价格标准了&#xff0c;说明他的价格要的非常的低&#xff0…

每日一题——LeetCode1704.判断字符串的两半是否相等

方法一 计数 从头到尾简历字符串&#xff0c;判断字符是否是元音字符&#xff0c;如果是再判断i的值是字符串前一半还是后一半&#xff0c;前一半sum1&#xff0c;后一半sum2 var halvesAreAlike function(s) {const h "aeiouAEIOU";let sum1 0, sum2 0;for (l…

TypeScript:typescript的安装与运行

TypeScript&#xff1a;typescript的安装与运行 1 安装方式 -g全局安装TypeScript&#xff1a; npm install -g typescript2 运行方式 &#xff08;1&#xff09;ts编译成js&#xff0c;使用node命令运行js文件 打开vscode&#xff0c;进入ts文件所在目录下并打开终端term…

微信小程序 canvas层级过高覆盖原生组件

一、背景 微信小程序中使用signature第三方插件完成签名效果&#xff0c;但真机调试时发现canvas层级过高遮挡了按钮 二、具体问题 问题原因&#xff1a;签名后点击按钮无法生效 问题代码&#xff1a; <template><view class"sign_page" v-cloak>&l…

MATLAB编译器配置:MinGW

使用 MATLAB 2022b版本&#xff0c;查询编译器时如上&#xff0c;想安装个MinGW编译器&#xff0c;自带的附加资源管理不好使&#xff0c;只能换个别的法子&#xff0c;经过一些参考&#xff0c;总结如下。 步骤1.在这里下载一个MinGW.最新版本是10.3.0.然后默认安装&#xff…

【好用】Star超36.8k,一个的免费通用数据库管理工具

关于数据库管理工具&#xff0c;大家可能都在用SQLyog、Navicat、MySQL-Front、SQL Studio、MySQL Workbench等等&#xff0c;这些管理工具不是不好用&#xff0c;就是要变魔术才可以用&#xff0c;今天 V 哥给大家推荐一个即好用&#xff0c;又免费的可视化通用数据库管理工具…

手机备忘录怎么导出到电脑,如何将手机备忘录导出到电脑

备忘录是我们日常生活和工作中常用的工具之一&#xff0c;我们可以在手机上轻松地记录重要的事务、想法和灵感。然而&#xff0c;在某些情况下&#xff0c;我们可能需要将手机备忘录导出到电脑进行更详细的整理和管理。那么&#xff0c;手机备忘录怎么导出到电脑&#xff0c;如…

如何设计一个kafka(理解)

因业务需要而对消息中间件的频繁使用后&#xff0c;每次总会问自己一个问题&#xff1a;kafka为什么快&#xff1f;然后再去背一背八卦找找答案。直到近日终于能站在一个新奇的角度理解kafka&#xff0c;且积累的各种细节串通了起来&#xff0c;实属惊喜。 回到最开始的问题&am…

VS Code安装

VS Code 安装 一、下载 进入VS Code官网&#xff1a;https://code.visualstudio.com&#xff0c;点击 DownLoad for Windows下载windows版本 Stable&#xff1a;稳定版Insiders&#xff1a;内测版 二、安装 双击安装包&#xff0c;选择我同意此协议&#xff0c;再点击下一步 …

【办公类-22-15】周计划系列(5-6)“周计划-06 周计划打印pdf(docx删除内容转PDF)“ (2024年调整版本)

作品展示 背景需求&#xff1a; 前期用docx&#xff08;删除第一页反思部分内容&#xff09;转PDF转png&#xff08;第一页&#xff09;的方式获得上传网页用的图片。 【办公类-22-14】周计划系列&#xff08;5-5&#xff09;“周计划-05 上传周计划png&#xff08;docx转PDF…

2. IS-IS 基础实验

2.1 IS-IS 配置实验 2.1.1 实验介绍 2.1.1.1 学习目标 1. 实现 IS-IS 协议基本配置 2. 实现 IS-IS 协议 DIS 优先级修改 3. 实现 IS-IS 协议网络类型修改 4. 实现 IS-IS 协议外部路由引入 5. 实现 IS-IS 接口 cost 修改 6. 实现 IS-IS 路由渗透配置 2.1.1.2 实验组网介…

【每日一题】1793. 好子数组的最大分数-2024.3.19

题目&#xff1a; 1793. 好子数组的最大分数 给你一个整数数组 nums &#xff08;下标从 0 开始&#xff09;和一个整数 k 。 一个子数组 (i, j) 的 分数 定义为 min(nums[i], nums[i1], ..., nums[j]) * (j - i 1) 。一个 好 子数组的两个端点下标需要满足 i < k < …

【web前端】CSS语法

CSS语法 1. CSS语法格式 通常情况下语法格式如下: 选择器{属性名:属性值;属性名:属性值;属性名:属性值;... }2. CSS添加方式 2.1 行内样式 直接将样式写在本行的标签内。 <h1><p style"font-size: 48px; color:red;";>行内样式测试</p></…

抖音视频批量提取软件|无水印视频下载

抖音视频批量提取软件&#xff0c;让您高效下载精彩内容&#xff01; 您是否经常需要下载抖音视频&#xff0c;但传统的下载方式繁琐且低效&#xff1f;别担心&#xff0c;我们为您提供了一款强大而智能的抖音视频批量提取软件&#xff0c;让您轻松实现下载无水印的精彩内容&am…

瑞云渲染邀请码怎么用?

瑞云渲染邀请码是用来提供注册用户的特殊权限或优惠的代码。最近&#xff0c;瑞云渲染在注册页面开放了填写邀请码的功能。对于新用户而言&#xff0c;在注册账号时可能不太了解邀请码的具体作用以及如何获取邀请码。下面我们一起来了解一下吧&#xff01; 瑞云渲染是什么&…

C语言技能数(知识点汇总)

C语言技能数&#xff08;知识点汇总&#xff09; C 语言概述特点不足之处 标准编程机制 数据类型变量数据类型字符类型整数类型符号位二进制的原码、反码和补码 浮点类型布尔类型 常量字面常量const 修饰的常变量#define定义的标识符常量枚举常量 sizeofsizeof(结构体)不要对 v…

视频技术1:使用ABLMediaServer推流rtsp

ABLMediaServer定位是高性能、高稳定、开箱即用、商用级别的流媒体服务器 下边展示了如何把1个mp3作为输入源&#xff0c;转换为rtsp流的过程。 作用&#xff1a;用rtsp模拟摄像头的视频流 1、启动ABLMediaServer ABLMediaServer-2024-03-13\WinX64\ABLMediaServer.exe 配…

nodejs 使用express插件multer文件上传,接收不到文件的bug

把路径改成绝对路径即可 改成 temp是你想上传到文件夹的路径&#xff0c;一般是在项目根目录下

蓝桥杯-python-递归

递归&#xff1a;通过自我调用解决问题的函数 注意&#xff1a; #1.递归出口 #2.当前问题如何变成子问题 例子&#xff1a;利用递归写一个阶乘函数&#xff0c;F(n),求n的阶乘 def f(n):if n < 1:return 1ans n * f(n-1)return ans print(f(5)) 例子&#xff1a;汉诺塔…