热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

openssl实现https网站

下面是一个用openssl实现获取https网页内容的demo,整个流程比较简单,主要封装的API如下staticinthttps_init(http

下面是一个用openssl  实现获取https 网页内容的demo,整个流程比较简单,主要封装的API如下

static int https_init(https_context_t *context,const char* url);
static int https_uninit(https_context_t *context);
static int https_read(https_context_t *context,void* buff,int len);
static int https_write(https_context_t *context,const void* buff,int len);
static int https_get_status_code(https_context_t *context);
static int https_read_content(https_context_t *context,char *resp_contet,int max_len);

通信流程:

1、初始化,解析url资源,创建socket 连接,绑定ssl

2、发送http 请求

3、获取请求返回的状态码

4、获取请求返回的数据

5、销毁动态申请的内存资源

我就把整个代码贴在下面


#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include #define HTTP_REQ_LENGTH 512
#define HTTP_RESP_LENGTH 20480typedef struct
{int sock_fd;SSL_CTX *ssl_ct;SSL *ssl;//url 解析出来的信息char *host;char *path;int port;
} https_context_t;static int https_init(https_context_t *context,const char* url);
static int https_uninit(https_context_t *context);
static int https_read(https_context_t *context,void* buff,int len);
static int https_write(https_context_t *context,const void* buff,int len);
static int https_get_status_code(https_context_t *context);
static int https_read_content(https_context_t *context,char *resp_contet,int max_len);// http 请求头信息
static char https_header[] ="GET %s HTTP/1.1\r\n""Host: %s:%d\r\n""Connection: Close\r\n""Accept: */*\r\n""\r\n";static char http_req_content[HTTP_REQ_LENGTH] = {0};
static char https_resp_content[HTTP_RESP_LENGTH+1] = {0};static int create_request_socket(const char* host,const int port)
{int sockfd;struct hostent *server;struct sockaddr_in serv_addr;sockfd &#61; socket(AF_INET, SOCK_STREAM, 0);if (sockfd <0){printf("[http_demo] create_request_socket create socket fail.\n");return -1;}/* lookup the ip address */server &#61; gethostbyname(host);if(server &#61;&#61; NULL){printf("[http_demo] create_request_socket gethostbyname fail.\n");close(sockfd);return -1;}memset(&serv_addr,0,sizeof(serv_addr));serv_addr.sin_family &#61; AF_INET;serv_addr.sin_port &#61; htons(port);memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) <0){printf("[http_demo] create_request_socket connect fail.\n");close(sockfd);return -1;}return sockfd;
}/*** &#64;brief https_parser_url 解析出https 中的域名、端口和路径* &#64;param url 需要解析的url* &#64;param host 解析出来的域名或者ip* &#64;param port 端口&#xff0c;没有时默认返回443* &#64;param path 路径&#xff0c;指的是域名后面的位置* &#64;return*/
static int https_parser_url(const char* url,char **host,int *port,char **path)
{if(url &#61;&#61; NULL || strlen(url) <9 || host &#61;&#61; NULL || path &#61;&#61; NULL){printf("[https_demo] url or host or path is null.\n");return -1;}//判断是不是 https://int i &#61; 0;char https_prefix[] &#61; "https://";for(i&#61;0;i<8;i&#43;&#43;){if(url[i] !&#61; https_prefix[i]){printf("[https_demo] illegal url &#61; %s.\n",url);return -1;}}const char *temp &#61; url&#43;i;while(*temp !&#61; &#39;/&#39;) //next /{if(*temp &#61;&#61; &#39;\0&#39;) //{printf("[https_demo] illegal url &#61; %s.\n",url);return -1;}temp&#43;&#43;;}const char *host_port &#61; url&#43;i;while(*host_port !&#61; &#39;:&#39; && *host_port !&#61; &#39;/&#39;) //找到 :或者 / 结束{host_port &#43;&#43;;}int host_len &#61; host_port-url-i; //减掉https://int path_len &#61; strlen(temp);char *host_temp &#61; (char *)malloc(host_len &#43; 1); //多一个字符串结束标识 \0if(host_temp &#61;&#61; NULL){printf("[https_demo] malloc host fail.\n");return -1;}if(*host_port&#43;&#43; &#61;&#61; &#39;:&#39;) //url 中有端口{*port &#61; 0;while(*host_port !&#61;&#39;/&#39; && *host_port !&#61;&#39;\0&#39;) //十进制字符串转成数字{*port *&#61; 10;*port &#43;&#61; (*host_port - &#39;0&#39;);host_port &#43;&#43;;}}else{*port &#61; 443;}char *path_temp &#61; (char *)malloc(path_len &#43; 1); //多一个字符串结束标识 \0if(path_temp &#61;&#61; NULL){printf("[https_demo] malloc path fail.\n");free(host_temp);return -1;}memcpy(host_temp,url&#43;i,host_len);memcpy(path_temp,temp,path_len);host_temp[host_len] &#61; &#39;\0&#39;;path_temp[path_len] &#61; &#39;\0&#39;;*host &#61; host_temp;*path &#61; path_temp;return 0;
}static int https_init(https_context_t *context,const char* url)
{if(context &#61;&#61; NULL){printf("[https_demo] init https_context_t is null.\n");return -1;}if(https_parser_url(url,&(context->host),&(context->port),&(context->path))){printf("[https_demo] https_parser_url fail.\n");return -1;}context->sock_fd &#61; create_request_socket(context->host,context->port);if(context->sock_fd <0){printf("[https_demo] create_request_socket fail.\n");goto https_init_fail;}context->ssl_ct &#61; SSL_CTX_new(SSLv23_method());if(context->ssl_ct &#61;&#61; NULL){printf("[https_demo] SSL_CTX_new fail.\n");goto https_init_fail;}context->ssl &#61; SSL_new(context->ssl_ct);if(context->ssl &#61;&#61; NULL){printf("[https_demo] SSL_new fail.\n");goto https_init_fail;}if(SSL_set_fd(context->ssl,context->sock_fd)<0){printf("[https_demo] SSL_set_fd fail \n");}if(SSL_connect(context->ssl) &#61;&#61; -1){printf("[https_demo] SSL_connect fail.\n");goto https_init_fail;}return 0;
https_init_fail:https_uninit(context);return -1;
}static int https_read(https_context_t *context,void* buff,int len)
{if(context &#61;&#61; NULL || context->ssl &#61;&#61; NULL){printf("[https_demo] read https_context_t or ssl is null.\n");return -1;}return SSL_read(context->ssl,buff,len);
}static int https_write(https_context_t *context,const void* buff,int len)
{if(context &#61;&#61; NULL || context->ssl &#61;&#61; NULL){printf("[https_demo] write https_context_t or ssl is null.\n");return -1;}return SSL_write(context->ssl,buff,len);
}static int https_get_status_code(https_context_t *context)
{if(context &#61;&#61; NULL || context->ssl &#61;&#61; NULL){printf("[https_demo] get status https_context_t or ssl is null.\n");return -1;}int ret;int flag &#61;0;int recv_len &#61; 0;char res_header[1024] &#61; {0};while(recv_len<1023){ret &#61; SSL_read(context->ssl, res_header&#43;recv_len, 1);if(ret<1) // recv fail{break;}//找到响应头的头部信息, 两个"\r\n"为分割点if((res_header[recv_len]&#61;&#61;&#39;\r&#39;&&(flag&#61;&#61;0||flag&#61;&#61;2))||(res_header[recv_len]&#61;&#61;&#39;\n&#39;&&(flag&#61;&#61;1||flag&#61;&#61;3))){flag&#43;&#43;;}else{flag &#61; 0;}recv_len&#43;&#61;ret;if(flag&#61;&#61;4){break;}}//printf("[http_demo] recv_len&#61;%d res_header &#61; %s.\n",recv_len,res_header);/*获取响应头的信息*/int status_code &#61; -1;char *pos &#61; strstr(res_header, "HTTP/");if(pos){sscanf(pos, "%*s %d", &status_code);//返回状态码}return status_code;
}static int https_read_content(https_context_t *context,char *resp_contet,int max_len)
{if(context &#61;&#61; NULL || context->ssl &#61;&#61; NULL){printf("[https_demo] read content https_context_t or ssl is null.\n");return -1;}int ret ;int recv_size &#61; 0;while(recv_size ssl,resp_contet &#43; recv_size,max_len-recv_size);if(ret <1){break;}recv_size &#43;&#61; ret;}return recv_size;
}static int https_uninit(https_context_t *context)
{if(context &#61;&#61; NULL){printf("[https_demo] uninit https_context_t is null.\n");return -1;}if(context->host !&#61; NULL){free(context->host);context->host &#61; NULL;}if(context->path !&#61; NULL){free(context->path);context->path &#61; NULL;}if(context->ssl !&#61; NULL){SSL_shutdown(context->ssl);//SSl_free(context->ssl);context->ssl &#61; NULL;}if(context->ssl_ct !&#61; NULL){SSL_CTX_free(context->ssl_ct);context->ssl_ct &#61; NULL;}if(context->sock_fd > 0){close(context->sock_fd);context->sock_fd &#61; -1;}return 0;
}int main()
{https_context_t https_ct &#61; {0};int ret &#61; SSL_library_init();printf("[https_demo] SSL_library_init ret &#61; %d.\n",ret);https_init(&https_ct,"https://www.baidu.com/");ret &#61; snprintf(http_req_content,HTTP_REQ_LENGTH,https_header,https_ct.path,https_ct.host,https_ct.port);ret &#61; https_write(&https_ct,http_req_content,ret);printf("[https_demo] https_write ret &#61; %d.\n",ret);if(https_get_status_code(&https_ct) &#61;&#61; 200){ret &#61; https_read_content(&https_ct,https_resp_content,HTTP_RESP_LENGTH);if(ret > 0){https_resp_content[ret] &#61; &#39;\0&#39;; //字符串结束标识printf("[https_demo] https_write https_resp_content &#61; \n %s.\n",https_resp_content);}}https_uninit(&https_ct);return 0;
}

 


推荐阅读
  • golang常用库:配置文件解析库/管理工具viper使用
    golang常用库:配置文件解析库管理工具-viper使用-一、viper简介viper配置管理解析库,是由大神SteveFrancia开发,他在google领导着golang的 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 使用 Azure Service Principal 和 Microsoft Graph API 获取 AAD 用户列表
    本文介绍了一段通用代码示例,该代码不仅能够操作 Azure Active Directory (AAD),还可以通过 Azure Service Principal 的授权访问和管理 Azure 订阅资源。Azure 的架构可以分为两个层级:AAD 和 Subscription。 ... [详细]
  • Explore how Matterverse is redefining the metaverse experience, creating immersive and meaningful virtual environments that foster genuine connections and economic opportunities. ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 火星商店问题:线段树分治与持久化Trie树的应用
    本题涉及编号为1至n的火星商店,每个商店有一个永久商品价值v。操作包括每天在指定商店增加一个新商品,以及查询某段时间内某些商店中所有商品(含永久商品)与给定密码值的最大异或结果。通过线段树分治和持久化Trie树来高效解决此问题。 ... [详细]
  • Java 中的 BigDecimal pow()方法,示例 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • 本文详细解析了Python中的os和sys模块,介绍了它们的功能、常用方法及其在实际编程中的应用。 ... [详细]
  • 本文探讨了如何通过最小生成树(MST)来计算严格次小生成树。在处理过程中,需特别注意所有边权重相等的情况,以避免错误。我们首先构建最小生成树,然后枚举每条非树边,检查其是否能形成更优的次小生成树。 ... [详细]
  • 如何在窗口右下角添加调整大小的手柄
    本文探讨了如何在传统MFC/Win32 API编程中实现类似C# WinForms中的SizeGrip功能,即在窗口的右下角显示一个用于调整窗口大小的手柄。我们将介绍具体的实现方法和相关API。 ... [详细]
  • 本文介绍了如何在C#中启动一个应用程序,并通过枚举窗口来获取其主窗口句柄。当使用Process类启动程序时,我们通常只能获得进程的句柄,而主窗口句柄可能为0。因此,我们需要使用API函数和回调机制来准确获取主窗口句柄。 ... [详细]
  • ServiceStack与Swagger的无缝集成指南
    本文详细介绍了如何在ServiceStack项目中集成Swagger,以实现API文档的自动生成和在线测试。通过本指南,您将了解从配置到部署的完整流程,并掌握如何优化API接口的开发和维护。 ... [详细]
author-avatar
111222
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有