#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdbool.h>
#include "gp.h"
// 定义一个函数,根据请求方法、URL和参数发送HTTP请求,并将响应和异常写入传入的缓冲区中
int sendHttpRequest(char *method, char *url, char *params,GP_HTTP_RESPONSE *res,char *err_message) {
// 创建一个URL结构体,解析URL中的主机名、端口号、路径等信息
struct URL {
char *protocol;
char *host;
int port;
char *path;
};
struct URL u; //定义请求信息结构体变量
SSL *ssl; //定义SSL结构体变量
bool is_https = false; //记录请求是不是https
char *response_buffer = (char *)malloc(GP_RESPONSE_BUFFER_LEN); //用于接收请求的临时缓冲区
//初始化ssl
SSL_CTX *ctx;
SSL_library_init();
OpenSSL_add_all_algorithms();
// 定义一个包含随机数据的缓冲区作为ssl加密随机数
static const char rnd_seed[] = "string to make the random number generator think it has entropy";
// 生成随机数
RAND_seed(rnd_seed, sizeof rnd_seed);
// 创建一个SSL_CTX对象,使用SSLv23_client_method方法
ctx = SSL_CTX_new(SSLv23_client_method());
if(ctx == NULL)
{
strcmp(err_message,"初始化ssl失败");
free(response_buffer);
return 1;
}
//允许请求方法使用小写
char *real_method;
if (strcmp(method,"GET") == 0 || strcmp(method,"get") == 0) {
method = "GET";
} else if (strcmp(method,"POST") == 0 || strcmp(method,"post") == 0) {
method = "POST";
} else {
method = method;
}
// 参数异常判断
if (method == NULL || url == NULL){
char *err = "lost method or url";
strcpy(err_message,err);
free(response_buffer);
return 1;
}
// 使用strtok函数分割URL字符串
int url_len = strlen(url); // 计算url字符串的长度
char *url_cut_host_protocol_buffer = malloc(url_len + 1); // 分配字符串空间用于分割,多出一个字节用来存储'\0'
memset(url_cut_host_protocol_buffer, 0, sizeof(url_cut_host_protocol_buffer)); // 初始化为0
strcpy(url_cut_host_protocol_buffer, url); //复制url的值到url字符切割缓冲区
//获取协议名
char *token = strtok(url_cut_host_protocol_buffer, ":/"); // 按照:和/任意有一个就替换分割
if ((token == NULL) || (strcmp(token,"http") != 0 && strcmp(token,"https")!=0) ){
char *err = "Invalid URL";
strcpy(err_message,err);
free(response_buffer);
free(url_cut_host_protocol_buffer); //释放用于分割协议和host的内存
return 1;
}
u.protocol = token; // 第一个分割出来的是协议
//获取主机名
token = strtok(NULL, ":/"); // 再次分割
if (strcmp(token, "") == 0) { // 如果分割出来的是空字符串,说明有//
token = strtok(NULL, ":/"); // 再次分割
u.host = token; // 这次分割出来的是主机名
} else {
u.host = token; // 否则直接是主机名
}
//获取uri路径
token = strtok(NULL, ":/"); //继续切割
char *path_cut_uri_buffer; //如果uri路径不是'/',就定义切割缓冲区
path_cut_uri_buffer = malloc(url_len + 1); // 分配字符串空间用于分割,多出一个字节用来存储'\0'
memset(path_cut_uri_buffer, 0, sizeof(path_cut_uri_buffer)); // 初始化为0
if (token == NULL){
u.path="/";
}else {
while (token != NULL) //循环切割路径
{
sprintf(path_cut_uri_buffer + strlen(path_cut_uri_buffer), "/%s", token); //拼接路径
token = strtok(NULL, ":/");
}
u.path = path_cut_uri_buffer;
}
//获取端口号
char *url_cut_port_buffer = malloc(url_len + 1); // 分配字符串空间用于分割,多出一个字节用来存储'\0'
memset(url_cut_port_buffer, 0, sizeof(url_cut_port_buffer)); // 初始化为0
strcpy(url_cut_port_buffer, url); // 复制path到字符切割缓冲区
token = strtok(url_cut_port_buffer, ":"); // 按照:分割
token = strtok(NULL, ":"); // 再次分割
token = strtok(NULL, ":"); // 再次分割
if (token == NULL) { // 如果没有分割出来,说明没有指定端口号
if (strcmp(u.protocol, "http") == 0) { // 如果协议是http,默认端口为80
u.port = 80;
} else if (strcmp(u.protocol, "https") == 0) { // 如果协议是https,默认端口为443
u.port = 443;
is_https = true;
} else { // 否则抛出异常
char *err = "Invalid Protocol";
strcpy(err_message,err);
free(response_buffer);
free(url_cut_host_protocol_buffer); //释放用于分割协议和host的内存
free(url_cut_port_buffer);// 释放用于分割端口号的内存
free(path_cut_uri_buffer); //释放用于分割uri的内存
return 1;
}
} else {
u.port = atoi(token); // 否则把分割出来的字符串转换成整数作为端口号
}
//构建服务器的信息体
struct sockaddr_in server_addr; // 定义一个服务器地址结构体
memset(&server_addr, 0, sizeof(server_addr)); // 初始化为0
server_addr.sin_family = AF_INET; // 地址族为IPv4
server_addr.sin_port = htons(u.port); // 端口号,注意转换成网络字节序
struct hostent *host = gethostbyname(u.host); // 根据主机名获取IP地址
if (host == NULL) { // 如果获取失败,抛出异常
char *err = "gethostbyname error";
strcpy(err_message,err);
free(response_buffer);
free(url_cut_host_protocol_buffer); //释放用于分割协议和host的内存
free(url_cut_port_buffer);// 释放用于分割端口号的内存
free(path_cut_uri_buffer); //释放用于分割uri的内存
return 1;
}
memcpy(&server_addr.sin_addr.s_addr, host->h_addr_list[0], host->h_length); // 把IP地址复制到服务器地址结构体中
// 创建一个Socket对象,连接到指定的主机和端口
int sock = socket(AF_INET, SOCK_STREAM, 0); // 创建一个IPv4的TCP套接字
if (sock < 0) { // 如果创建失败,抛出异常
char *err ="socket error";
strcpy(err_message,err);
free(response_buffer);
free(url_cut_host_protocol_buffer); //释放用于分割协议和host的内存
free(url_cut_port_buffer);// 释放用于分割端口号的内存
free(path_cut_uri_buffer); //释放用于分割uri的内存
return 1;
}
//创建socket连接
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { // 连接到服务器,如果失败,抛出异常
char *err = "connect error";
strcpy(err_message,err);
free(response_buffer);
free(url_cut_host_protocol_buffer); //释放用于分割协议和host的内存
free(url_cut_port_buffer);// 释放用于分割端口号的内存
free(path_cut_uri_buffer); //释放用于分割uri的内存
return 1;
}
if(is_https){
// 创建一个SSL对象
ssl = SSL_new(ctx);
if(ssl == NULL)
{
// 如果创建失败,打印错误信息并返回-1
ERR_print_errors_fp(stderr);
free(response_buffer);
free(url_cut_host_protocol_buffer); //释放用于分割协议和host的内存
free(url_cut_port_buffer);// 释放用于分割端口号的内存
free(path_cut_uri_buffer); //释放用于分割uri的内存
return -2;
}
// 将SSL对象和socket绑定
SSL_set_fd(ssl, sock);
// 建立SSL连接
if(SSL_connect(ssl) == -1)
{
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
库都用底层的写的,基本linux系统各个平台和编译器新旧都通用 使用参考:https://blog.csdn.net/qq_31923639/article/details/130466084?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22130466084%22%2C%22source%22%3A%22qq_31923639%22%7D
资源推荐
资源详情
资源评论
收起资源包目录
c_get_posst.zip (2个子文件)
gp.c 16KB
gp.h 524B
共 2 条
- 1
资源评论
我的小帽子歪了
- 粉丝: 2
- 资源: 4
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功