• QQ
  • nahooten@sina.com
  • 常州市九洲新世界花苑15-2

技术天地

libevent和libcurl完成http和https服务 cJSON运用

原创内容,转载请注明原文网址:http://homeqin.cn/a/wenzhangboke/jishutiandi/2019/0917/644.html

  前言
  libevent和libcurl都是功用强大的开源库;libevent主要完成效劳器,包含了select、epoll等高并发的完成;libcurl完成了curl命令的API封装,主要作为客户端。
 
  一、常州游戏开发培训curl的两种运用办法
  1、命令行形式
    所谓命令行形式,就是直接linux的命令行直接能够执行的curl命令,curl能够做很多事情,我主要引见作为客户端发送xml和json数据,由于命令行形式十分要留意格式问题!
 
  (1)发送xml格式数据
  格式如下:
 
  
 
复制代码
echo '<?xml version="1.0" encoding="UTF-8"?>
 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:itsm="http://itsm.soa.csg.cn/">
   <soapenv:Header xmlns:auth="http://itsm.soa.csg.cn/">
     local_admin
     local_admin
   
   
     
       1
       
         
           测试虚拟机181106
           11.11.22.23
           设备帐户
           administrator
         
       
     
   
 
 '|curl -X POST -H 'Content-type:text/xml' -d @- http://10.94.1.167:80/ITSMWebServer/itsm
复制代码
  阐明:
 
echo后面跟的是手机App外包xml格式数据,格式普通都是跟第三方平台商定好的,不能发这种格式,接纳又是另一种格式,那没法解析了,都要提早商定好的!
中间是“|”管道符,将echo的输出作为curl的输入
POST 阐明是post恳求
-H 携带的音讯头
最后的url,是要发送的地址
  (2)发送json格式数据
  格式如下:
 
  
 
curl -H "Content-Type:application/json" -H "appName:spvas" -H "password:123123" -H "pswdHashType:SHA1" -X POST  -k -g -d '{"param":[{"objectID":112,"type":1,"operate":1,"operatorID":100,"result":0,"time":1539941168,"policytype":0}]}' http://172.16.1.21:9999/rest/spvas/objChange.do
  阐明:
 
  -H 仍然是音讯头
       -d  后面是json格式的数据了
  2、libcurl库运用
  1、装置
  想要运用libcurl库,首先需求先装置,装置参考我的这篇博客写的很细致:https://www.cnblogs.com/liudw-0215/p/9917422.html
 
  2、运用libcurl的API
  主要就是调用libcurl库的API接口,下面引见的http的POST恳求,libcurl很多接口,不能逐个引见,需求时能够再去查找。
 
  (1)初始化curl句柄
 
CURL* curl = NULL;
curl = curl_easy_init();
    (2)设置curl的url
 
curl_easy_setopt(curl, CURLOPT_URL, "http://172.16.1.96:7777/login");
  (3)开启post恳求开关
 
curl_easy_setopt(curl, CURLOPT_POST, true);
  (4)添加post数据
 
 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_str);
  (5)设定一个处置效劳器响应的回调函数
 
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, deal_response);
  (6)给回调函数传送一个形参
 
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseData);
  (7)向效劳器发送恳求,等候效劳器的响应
 
res = curl_easy_perform(curl);
  3、总体代码
 App开发培训客户端总体代码如下:
 
  
 
 
复制代码
//
// Created by ldw on 2018/11/8.
//
#include "cJSON.h"
#include <curl/curl.h>
#include<string.h>
#define RESPONSE_DATA_LEN 4096
//用来接纳效劳器一个buffer
typedef struct login_response_data
{
    login_response_data() {
        memset(data, 0, RESPONSE_DATA_LEN);
        data_len = 0;
    }
    char data[RESPONSE_DATA_LEN];
    int data_len;
}response_data_t;
//处置从效劳器返回的数据,将数据拷贝到arg中
size_t deal_response(void *ptr, size_t n, size_t m, void *arg)
{
    int count = m*n;
    response_data_t *response_data = (response_data_t*)arg;
    memcpy(response_data->data, ptr, count);
    response_data->data_len = count;
    return response_data->data_len;
}
#define POSTDATA "{\"username\":\"gailun\",\"password\":\"123123\",\"driver\":\"yes\"}"
int main()
{
    
    char *post_str = NULL;
   
    CURL* curl = NULL;
    CURLcode res;
    response_data_t responseData;//特地用来寄存从效劳器返回的数据
    //初始化curl句柄
    curl = curl_easy_init();
    if(curl == NULL) {
        return 1;
    }
    //封装常州网站开发培训一个数据协议
    /*
       ====给效劳端的协议====
     http://ip:port/login [json_data]
    {
        username: "gailun",
        password: "123123",
        driver:   "yes"
    }
     *
     *
     * */
    //(1)封装一个json字符串
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "username", "ldw");
    cJSON_AddStringToObject(root, "password", "123123");
    cJSON_AddStringToObject(root, "driver", "yes");
    post_str = cJSON_Print(root);
    cJSON_Delete(root);
    root = NULL;
    //(2) 向web效劳器 发送http恳求 其中post数据 json字符串
    //1 设置curl url
    curl_easy_setopt(curl, CURLOPT_URL, "http://172.16.1.96:7777/login");
    //客户端疏忽CA证书认证 用于https跳过证书认证
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
    //2 开启post恳求开关
    curl_easy_setopt(curl, CURLOPT_POST, true);
    //3 添加post数据
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_str);
    //4 设定一个处置效劳器响应的回调函数
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, deal_response);
    //5 给回调函数传送一个形参
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseData);
    //6 向效劳器发送恳求,等候效劳器的响应
    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        return 1;
    }
    curl_easy_cleanup(curl);
    
    //(3)  处置效劳器响应的数据 此刻的responseData就是从效劳器获取的数据
    /*
      //胜利
    {
        result: "ok",
    }
    //失败
    {
        result: "error",
        reason: "why...."
    }
     *
     * */
    //(4) 解析效劳器返回的json字符串
    //cJSON *root;
    root = cJSON_Parse(responseData.data);
    cJSON *result = cJSON_GetObjectItem(root, "result");
    if(result && strcmp(result->valuestring, "ok") == 0) {
        printf("data:%s\n",responseData.data);
        //登陆胜利
        return 0;
    }
    else {
        //登陆失败
        cJSON* reason = cJSON_GetObjectItem(root, "reason");
        if (reason) {
            //已知错误
           return 1;
        }
        else {
            //未知的错误
          return 1;
        }
        return 1;
    }
    return 0;
}
复制代码
  这是客户端的总体代码,但是还无法测试,由于没有效劳端,下面会引见用libevent库来搭建http的效劳端;由于数据格式是json,所以用到了cJSON,能够到我的github上停止下载,编译命令:g++ login.cpp cJSON.cpp -o login -lcurl
 
  二、libevent库
 1、装置
    libevent仍然是开源库,运用之前仍然需求装置,装置参考我的这篇博客写的很细致:https://www.cnblogs.com/liudw-0215/p/9917422.html
 
  2、搭建http效劳器
    装置之后,就能够运用了,主要都是调用libcurl库的API函数,main函数如下:
 
复制企业培训代码
int main(int argc, char *argv[]) {
    //自定义信号处置函数
    signal(SIGHUP, signal_handler);
    signal(SIGTERM, signal_handler);
    signal(SIGINT, signal_handler);
    signal(SIGQUIT, signal_handler);
    //默许参数
    char *httpd_option_listen = "0.0.0.0";
    int httpd_option_port = 7777;
    int httpd_option_daemon = 0;
    int httpd_option_timeout = 120; //in seconds
    //获取参数
    int c;
    while ((c = getopt(argc, argv, "l:p:dt:h")) != -1) {
        switch (c) {
            case 'l' :
                httpd_option_listen = optarg;
                break;
            case 'p' :
                httpd_option_port = atoi(optarg);
                break;
            case 'd' :
                httpd_option_daemon = 1;
                break;
            case 't' :
                httpd_option_timeout = atoi(optarg);
                break;
            case 'h' :
            default :
                show_help();
                exit(EXIT_SUCCESS);
        }
    }
    //判别能否设置了-d,以daemon运转
    if (httpd_option_daemon) {
        pid_t pid;
        pid = fork();
        if (pid < 0) {
            perror("fork failed");
            exit(EXIT_FAILURE);
        }
        if (pid > 0) {
            //生成子进程胜利,退出父进程
            exit(EXIT_SUCCESS);
        }
    }
    /* 运用libevent创立HTTP Server */
    //初始化event API
    event_init();
    //创立一个http server
    struct evhttp *httpd;
    httpd = evhttp_start(httpd_option_listen, httpd_option_port);
    evhttp_set_timeout(httpd, httpd_option_timeout);
    //也能够为特定的URI指定callback
    evhttp_set_cb(httpd, "/", httpd_handler, NULL);
    evhttp_set_cb(httpd, "/login", login_handler, NULL);
    //循环处置events
    event_dispatch();
    evhttp_free(httpd);
    return 0;
}
复制代码
   3、测试http效劳
  启动效劳端  
  从我的github上下载之后,http效劳在libcurl/http_server/这个目录,写Makefile,然后直接make就能够了,如下:
 
  
 
  make之后生成了server,执行:./server,启动效劳
 
  启动常州软件技术培训客户端
  在libcurl/login/这个目录,执行:g++ login.cpp cJSON.cpp -o login -lcurl,停止编译,生成login,启动客户端:./login,客户端运转结果,如下:
 
  
 
  效劳端响应结果,如下:
 
  
 
  至此,完成了演示,用libcurl和libevent搭建的http效劳器与客户端,没有问题。是不是觉得到此就完毕了,才没有呢?下面,将要引见https效劳器,那为什么要用https效劳器呢?跟随我找到谜底吧!
 
  4、搭建https效劳器
  (1)https引见
  http传输过程都是明文传输,很不平安;就产生https,停止加密传输,但加密过程并没有那么简单,如下图所示:
 
  
 
  阐明:
 
  主要阅历了两个阶段:
 
  非对称加密过程
  经过公钥、私钥和CA证书,停止考证,最终取得会话密钥
 
  对称加密过程
  可能会想?直接都用非对称加密得了,为啥用对称加密?由于非对称效率很低,所以要用对称加密!
 
  用非对称过程得到的密钥,对数据停止加密然后传输。
 
  (2)https效劳器完成
  libevent库应该从2.1版本之后才支持https的,所以在2.1之前的版本还要单独装置openssl!
 
  mian函数如下:
 
  
 
复制代码
int main (int argc, char **argv)
    /*OpenSSL 初始化 */
    common_setup ();              
    if (argc > 1) {
        char *end_ptr;
        long lp = strtol(argv[1], &end_ptr, 0);
        if (*end_ptr) {
            fprintf(stderr, "Invalid integer\n");
            return -1;
        }
        if (lp <= 0) {
            fprintf(stderr, "Port must be positive\n");
            return -1;
        }
        if (lp >= USHRT_MAX) {
            fprintf(stderr, "Port must fit 16-bit range\n");
            return -1;
        }
        serverPort = (unsigned short)lp;
    }
    /* now run http server (never returns) */
    return serve_some_http ();
}
复制代码
  (3)测试https效劳器
  启动效劳端  
  从我的github上下载之后,http效劳在libcurl/https_server/这个目录,写Makefile,然后直接make就能够了;
 
  启动客户端
  修正http的客户端就能够了,如下:
 
  
 
curl_easy_setopt(curl, CURLOPT_URL, "https://172.16.1.96:8080/login");
 
//客户端疏忽CA证书认证 用于https跳过证书认证
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
  阐明:
 
  在http后面加上“s”;再加上跳过证书认证,就能够了
 
  

上篇:上一篇:织梦dedecms文章页加转载链接的办法
下篇:下一篇:C/C++完成HTTPS通讯(抓取百度页面)