当前位置:   article > 正文

libevent和libcurl实现http和https服务器 cJSON使用_libcurl库可以做http服务器吗

libcurl库可以做http服务器吗

  前言

  libevent和libcurl都是功能强大的开源库;libevent主要实现服务器,包含了select、epoll等高并发的实现;libcurl实现了curl命令的API封装,主要作为客户端。这两个开源库的安装可以参考我的这篇博客:https://www.cnblogs.com/liudw-0215/p/9917422.html,并且我的代码都提交在了我的github上了,可以点左上角图标,跳转到github,仓库是libcurl。

  一、curl的两种使用方法

  1、命令行模式

    所谓命令行模式,就是直接linux的命令行直接可以执行的curl命令,curl可以做很多事情,我主要介绍作为客户端发送xml和json数据,因为命令行模式非常要注意格式问题!

  (1)发送xml格式数据

  格式如下:

  1. echo '<?xml version="1.0" encoding="UTF-8"?>
  2. <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:itsm="http://itsm.soa.csg.cn/">
  3. <soapenv:Header xmlns:auth="http://itsm.soa.csg.cn/">
  4. <auth:user>local_admin</auth:user>
  5. <auth:password>local_admin</auth:password>
  6. </soapenv:Header>
  7. <soapenv:Body>
  8. <itsm:accountOper>
  9. <operType>1</operType>
  10. <operItems>
  11. <operItem>
  12. <deviceName>测试虚拟机181106</deviceName>
  13. <deviceIP>11.11.22.23</deviceIP>
  14. <protocol>设备帐户</protocol>
  15. <accountName>administrator</accountName>
  16. </operItem>
  17. </operItems>
  18. </itsm:accountOper>
  19. </soapenv:Body>
  20. </soapenv:Envelope>
  21. '|curl -X POST -H 'Content-type:text/xml' -d @- http://10.94.1.167:80/ITSMWebServer/itsm

  说明:

    • echo后面跟的是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句柄

  1. CURL* curl = NULL;
  2. 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、总体代码

 客户端总体代码如下:

  1. //
  2. // Created by ldw on 2018/11/8.
  3. //
  4. #include "cJSON.h"
  5. #include <curl/curl.h>
  6. #include<string.h>
  7. #define RESPONSE_DATA_LEN 4096
  8. //用来接收服务器一个buffer
  9. typedef struct login_response_data
  10. {
  11. login_response_data() {
  12. memset(data, 0, RESPONSE_DATA_LEN);
  13. data_len = 0;
  14. }
  15. char data[RESPONSE_DATA_LEN];
  16. int data_len;
  17. }response_data_t;
  18. //处理从服务器返回的数据,将数据拷贝到arg中
  19. size_t deal_response(void *ptr, size_t n, size_t m, void *arg)
  20. {
  21. int count = m*n;
  22. response_data_t *response_data = (response_data_t*)arg;
  23. memcpy(response_data->data, ptr, count);
  24. response_data->data_len = count;
  25. return response_data->data_len;
  26. }
  27. #define POSTDATA "{\"username\":\"gailun\",\"password\":\"123123\",\"driver\":\"yes\"}"
  28. int main()
  29. {
  30. char *post_str = NULL;
  31. CURL* curl = NULL;
  32. CURLcode res;
  33. response_data_t responseData;//专门用来存放从服务器返回的数据
  34. //初始化curl句柄
  35. curl = curl_easy_init();
  36. if(curl == NULL) {
  37. return 1;
  38. }
  39. //封装一个数据协议
  40. /*
  41. ====给服务端的协议====
  42. http://ip:port/login [json_data]
  43. {
  44. username: "gailun",
  45. password: "123123",
  46. driver: "yes"
  47. }
  48. *
  49. *
  50. * */
  51. //(1)封装一个json字符串
  52. cJSON *root = cJSON_CreateObject();
  53. cJSON_AddStringToObject(root, "username", "ldw");
  54. cJSON_AddStringToObject(root, "password", "123123");
  55. cJSON_AddStringToObject(root, "driver", "yes");
  56. post_str = cJSON_Print(root);
  57. cJSON_Delete(root);
  58. root = NULL;
  59. //(2) 向web服务器 发送http请求 其中post数据 json字符串
  60. //1 设置curl url
  61. curl_easy_setopt(curl, CURLOPT_URL, "http://172.16.1.96:7777/login");
  62. //客户端忽略CA证书认证 用于https跳过证书认证
  63. curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
  64. curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
  65. //2 开启post请求开关
  66. curl_easy_setopt(curl, CURLOPT_POST, true);
  67. //3 添加post数据
  68. curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_str);
  69. //4 设定一个处理服务器响应的回调函数
  70. curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, deal_response);
  71. //5 给回调函数传递一个形参
  72. curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseData);
  73. //6 向服务器发送请求,等待服务器的响应
  74. res = curl_easy_perform(curl);
  75. if (res != CURLE_OK) {
  76. return 1;
  77. }
  78. curl_easy_cleanup(curl);
  79. //(3) 处理服务器响应的数据 此刻的responseData就是从服务器获取的数据
  80. /*
  81. //成功
  82. {
  83. result: "ok",
  84. }
  85. //失败
  86. {
  87. result: "error",
  88. reason: "why...."
  89. }
  90. *
  91. * */
  92. //(4) 解析服务器返回的json字符串
  93. //cJSON *root;
  94. root = cJSON_Parse(responseData.data);
  95. cJSON *result = cJSON_GetObjectItem(root, "result");
  96. if(result && strcmp(result->valuestring, "ok") == 0) {
  97. printf("data:%s\n",responseData.data);
  98. //登陆成功
  99. return 0;
  100. }
  101. else {
  102. //登陆失败
  103. cJSON* reason = cJSON_GetObjectItem(root, "reason");
  104. if (reason) {
  105. //已知错误
  106. return 1;
  107. }
  108. else {
  109. //未知的错误
  110. return 1;
  111. }
  112. return 1;
  113. }
  114. return 0;
  115. }

  这是客户端的总体代码,但是还无法测试,因为没有服务端,下面会介绍用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函数如下:

  1. int main(int argc, char *argv[]) {
  2. //自定义信号处理函数
  3. signal(SIGHUP, signal_handler);
  4. signal(SIGTERM, signal_handler);
  5. signal(SIGINT, signal_handler);
  6. signal(SIGQUIT, signal_handler);
  7. //默认参数
  8. char *httpd_option_listen = "0.0.0.0";
  9. int httpd_option_port = 7777;
  10. int httpd_option_daemon = 0;
  11. int httpd_option_timeout = 120; //in seconds
  12. //获取参数
  13. int c;
  14. while ((c = getopt(argc, argv, "l:p:dt:h")) != -1) {
  15. switch (c) {
  16. case 'l' :
  17. httpd_option_listen = optarg;
  18. break;
  19. case 'p' :
  20. httpd_option_port = atoi(optarg);
  21. break;
  22. case 'd' :
  23. httpd_option_daemon = 1;
  24. break;
  25. case 't' :
  26. httpd_option_timeout = atoi(optarg);
  27. break;
  28. case 'h' :
  29. default :
  30. show_help();
  31. exit(EXIT_SUCCESS);
  32. }
  33. }
  34. //判断是否设置了-d,以daemon运行
  35. if (httpd_option_daemon) {
  36. pid_t pid;
  37. pid = fork();
  38. if (pid < 0) {
  39. perror("fork failed");
  40. exit(EXIT_FAILURE);
  41. }
  42. if (pid > 0) {
  43. //生成子进程成功,退出父进程
  44. exit(EXIT_SUCCESS);
  45. }
  46. }
  47. /* 使用libevent创建HTTP Server */
  48. //初始化event API
  49. event_init();
  50. //创建一个http server
  51. struct evhttp *httpd;
  52. httpd = evhttp_start(httpd_option_listen, httpd_option_port);
  53. evhttp_set_timeout(httpd, httpd_option_timeout);
  54. //也可以为特定的URI指定callback
  55. evhttp_set_cb(httpd, "/", httpd_handler, NULL);
  56. evhttp_set_cb(httpd, "/login", login_handler, NULL);
  57. //循环处理events
  58. event_dispatch();
  59. evhttp_free(httpd);
  60. return 0;
  61. }

   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函数如下:

  1. int main (int argc, char **argv)
  2. {
  3. /*OpenSSL 初始化 */
  4. common_setup ();
  5. if (argc > 1) {
  6. char *end_ptr;
  7. long lp = strtol(argv[1], &end_ptr, 0);
  8. if (*end_ptr) {
  9. fprintf(stderr, "Invalid integer\n");
  10. return -1;
  11. }
  12. if (lp <= 0) {
  13. fprintf(stderr, "Port must be positive\n");
  14. return -1;
  15. }
  16. if (lp >= USHRT_MAX) {
  17. fprintf(stderr, "Port must fit 16-bit range\n");
  18. return -1;
  19. }
  20. serverPort = (unsigned short)lp;
  21. }
  22. /* now run http server (never returns) */
  23. return serve_some_http ();
  24. }

  (3)测试https服务器

  •   启动服务端  

  从我的github上下载之后,http服务在libcurl/https_server/这个目录,写Makefile,然后直接make就可以了;

  •   启动客户端

  修改http的客户端就可以了,如下:

  

  1. curl_easy_setopt(curl, CURLOPT_URL, "https://172.16.1.96:8080/login");
  2. //客户端忽略CA证书认证 用于https跳过证书认证
  3. curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
  4. curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);

  说明:

  在http后面加上“s”;再加上跳过证书认证,就可以了

  

  

  

  

作者:逆袭之路

出处:https://www.cnblogs.com/liudw-0215/

-------------------------------------------

个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!

如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!

 

万水千山总是情,打赏一分行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主,哈哈哈(っ•̀ω•́)っ✎⁾⁾!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/685473
推荐阅读
相关标签
  

闽ICP备14008679号