热门标签 | 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;
}

 


推荐阅读
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • 本文详细介绍了 GWT 中 PopupPanel 类的 onKeyDownPreview 方法,提供了多个代码示例及应用场景,帮助开发者更好地理解和使用该方法。 ... [详细]
  • 本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ... [详细]
  • 导航栏样式练习:项目实例解析
    本文详细介绍了如何创建一个具有动态效果的导航栏,包括HTML、CSS和JavaScript代码的实现,并附有详细的说明和效果图。 ... [详细]
  • 主要用了2个类来实现的,话不多说,直接看运行结果,然后在奉上源代码1.Index.javaimportjava.awt.Color;im ... [详细]
  • 题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 本文探讨了 Objective-C 中的一些重要语法特性,包括 goto 语句、块(block)的使用、访问修饰符以及属性管理等。通过实例代码和详细解释,帮助开发者更好地理解和应用这些特性。 ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • 在前两篇文章中,我们探讨了 ControllerDescriptor 和 ActionDescriptor 这两个描述对象,分别对应控制器和操作方法。本文将基于 MVC3 源码进一步分析 ParameterDescriptor,即用于描述 Action 方法参数的对象,并详细介绍其工作原理。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 本文介绍如何使用 NSTimer 实现倒计时功能,详细讲解了初始化方法、参数配置以及具体实现步骤。通过示例代码展示如何创建和管理定时器,确保在指定时间间隔内执行特定任务。 ... [详细]
  • 本文详细介绍了Java中org.w3c.dom.Text类的splitText()方法,通过多个代码示例展示了其实际应用。该方法用于将文本节点在指定位置拆分为两个节点,并保持在文档树中。 ... [详细]
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社区 版权所有