OpenHarmony开发者论坛

标题: 实现OpenHarmony简单的Http客户端 [打印本页]

作者: 深开鸿_王石    时间: 2023-12-21 10:16
标题: 实现OpenHarmony简单的Http客户端
[md]#### 概述

* **HTTP 是一个基于 TCP/IP 通信协议来传递数据(HTML 文件、图片文件、查询结果等);**
* **HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。目前在WWW中使用的是HTTP/1.0的第六版,HTTP/1.1的规范化工作正在进行之中,而且HTTP-NG(Next Generation of HTTP)的建议已经提出;**
* **HTTP协议工作于客户端-服务端架构为上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息;**

#### HTTP请求消息Request

* **请求数据结构如下**

  ![image.png](https://forums-obs.openharmony.c ... 9j9kgkrebrkwezo.png "image.png")
* **一个Get的sample**

**在浏览器输入**[www.baidu.com](www.baidu.com)然后回车即可看到浏览器显示了百度的页面,按F12可以看到具体内容:

![image.png](https://forums-obs.openharmony.c ... 55ntre4cn2fi2w2.png "image.png")

**上图里我们可以看到在请求的url是**[www.baidu.com](www.baidu.com),请求的方法是GET,服务器的IP地址是180.101.49.14:443(https,若是http就是80)

* **一个Post的sample**

  ![image.png](https://forums-obs.openharmony.c ... kp7aaacirrqppko.png "image.png")

  **上图里我们可以看到在请求的url是**[https://cysz.hopethink.com/qhhsd/app/getH5HsdList](https://cysz.hopethink.com/qhhsd/app/getH5HsdList),请求的方法是POST,服务器的IP地址是114.215.124.251:443(https,若是http就是80),请求内容类型application/x-www-form-urlencoded;charset=UTF-8,请求数据长度84,请求数据

**此样例参考小熊派设计,使用小熊派HM\_Micro开发板进行验证**

#### 应用开发流程

<pre class="md-fences md-end-block md-diagram md-fences-advanced ty-contain-cm modeLoaded" spellcheck="false" lang="mermaid" cid="n29" mdtype="fences" mermaid-type="graph"><div class="md-diagram-panel md-fences-adv-panel"><div class="md-diagram-panel-header"></div><div class="md-diagram-panel-preview"><svg id="mermaidChart0" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="61.59375" viewBox="0 0 754.65625 61.59375" class="in-text-selection"><g><g class="output"><g class="clusters"></g><g class="edgePaths"><g class="edgePath LS-建立build.gn LE-建立helloworld.c" id="L-建立build.gn-建立helloworld.c"><path class="path" d="M122.78125,30.796875L147.78125,30.796875L172.78125,30.796875" marker-end="url(#arrowhead22)"></path><defs><marker id="arrowhead22" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath"></path></marker></defs></g><g class="edgePath LS-建立helloworld.c LE-添加httpget" id="L-建立helloworld.c-添加httpget"><path class="path" d="M317.640625,30.796875L342.640625,30.796875L367.640625,30.796875" marker-end="url(#arrowhead23)"></path><defs><marker id="arrowhead23" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath"></path></marker></defs></g><g class="edgePath LS-添加httpget LE-添加httppost" id="L-添加httpget-添加httppost"><path class="path" d="M476.90625,30.796875L501.90625,30.796875L526.90625,30.796875" marker-end="url(#arrowhead24)"></path><defs><marker id="arrowhead24" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath"></path></marker></defs></g><g class="edgePath LS-添加httppost LE-验证" id="L-添加httppost-验证"><path class="path" d="M644.65625,30.796875L669.65625,30.796875L694.65625,30.796875" marker-end="url(#arrowhead25)"></path><defs><marker id="arrowhead25" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform=""><g transform="translate(0,0)" class="label"><rect rx="0" ry="0" width="0" height="0"></rect><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml"><span id="L-L-建立build.gn-建立helloworld.c" class="edgeLabel L-LS-建立build.gn' L-LE-建立helloworld.c"></span></div></foreignObject></g></g><g class="edgeLabel" transform=""><g transform="translate(0,0)" class="label"><rect rx="0" ry="0" width="0" height="0"></rect><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml"><span id="L-L-建立helloworld.c-添加httpget" class="edgeLabel L-LS-建立helloworld.c' L-LE-添加httpget"></span></div></foreignObject></g></g><g class="edgeLabel" transform=""><g transform="translate(0,0)" class="label"><rect rx="0" ry="0" width="0" height="0"></rect><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml"><span id="L-L-添加httpget-添加httppost" class="edgeLabel L-LS-添加httpget' L-LE-添加httppost"></span></div></foreignObject></g></g><g class="edgeLabel" transform=""><g transform="translate(0,0)" class="label"><rect rx="0" ry="0" width="0" height="0"></rect><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml"><span id="L-L-添加httppost-验证" class="edgeLabel L-LS-添加httppost' L-LE-验证"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node default" id="flowchart-建立build.gn-5" transform="translate(65.390625,30.796875)"><rect rx="0" ry="0" x="-57.390625" y="-22.796875" width="114.78125" height="45.59375" class="label-container"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-47.390625,-12.796875)"><foreignObject width="94.78125" height="25.59375"><div xmlns="http://www.w3.org/1999/xhtml">建立build.gn</div></foreignObject></g></g></g><g class="node default" id="flowchart-建立helloworld.c-6" transform="translate(245.2109375,30.796875)"><rect rx="0" ry="0" x="-72.4296875" y="-22.796875" width="144.859375" height="45.59375" class="label-container"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-62.4296875,-12.796875)"><foreignObject width="124.859375" height="25.59375"><div xmlns="http://www.w3.org/1999/xhtml">建立helloworld.c</div></foreignObject></g></g></g><g class="node default" id="flowchart-添加httpget-7" transform="translate(422.2734375,30.796875)"><rect rx="0" ry="0" x="-54.6328125" y="-22.796875" width="109.265625" height="45.59375" class="label-container"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-44.6328125,-12.796875)"><foreignObject width="89.265625" height="25.59375"><div xmlns="http://www.w3.org/1999/xhtml">添加httpget</div></foreignObject></g></g></g><g class="node default" id="flowchart-添加httppost-8" transform="translate(585.78125,30.796875)"><rect rx="0" ry="0" x="-58.875" y="-22.796875" width="117.75" height="45.59375" class="label-container"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-48.875,-12.796875)"><foreignObject width="97.75" height="25.59375"><div xmlns="http://www.w3.org/1999/xhtml">添加httppost</div></foreignObject></g></g></g><g class="node default" id="flowchart-验证-9" transform="translate(720.65625,30.796875)"><rect rx="0" ry="0" x="-26" y="-22.796875" width="52" height="45.59375" class="label-container"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-16,-12.796875)"><foreignObject width="32" height="25.59375"><div xmlns="http://www.w3.org/1999/xhtml">验证</div></foreignObject></g></g></g></g></g></g></svg></div><div class="md-diagram-panel-error"></div></div></pre>

1. **建立Build.gn**
   ```
   import("//build/lite/config/component/lite_component.gni")

   executable("hello_world_lib") {
       output_name = "hello_world"
       sources = [ "hello_world.c" ]
       include_dirs = []
       defines = []
       cflags_c = []
       ldflags = []
   }

   lite_component("my_app") {
       features = [
           ":hello_world_lib",
       ]
   }
   ```
2. **建立helloworld.c**
   ```
   #include <stdio.h>
   int main(int argc, char **argv)
   {
       printf("\n************************************************\n");
       printf("\n\t\tHello httpget!\n");
       printf("\n************************************************\n\n");
       
       return 0;
   }
   ```
3. **添加httpget**
   ```
   int sockfd, ret, i, h;
   struct sockaddr_in servaddr;
   char str1[BUF_SIZE], str2[BUF_SIZE], buf[BUF_SIZE], *str;
   socklen_t len;
   fd_set   t_set1;
   struct timeval  tv;
           
   //创建套接字
   if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
       printf("create socket failed--- exit(0)!\n");
       exit(0);
   };

   bzero(&servaddr, sizeof(servaddr));
   servaddr.sin_family = AF_INET;
   servaddr.sin_port = htons(PORT);
   if (inet_pton(AF_INET, IPSTR_GET, &servaddr.sin_addr) <= 0 ){
       printf("inet_pton failed --- exit(0)!\n");
       exit(0);
   };

   if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){
       printf("connect failed, exit(0)!\n");
       exit(0);
   }
   printf("connect remote server\n");
   memset(str2, 0, BUF_SIZE);
   strcat(str2, "theDataToGet");
   str=(char *)malloc(BUF_SIZE);
   len = strlen(str2);
   sprintf(str, "%d", len);
   //请求头部内容
   memset(str1, 0, BUF_SIZE);
   strcat(str1, "GET / HTTP/1.1\n");
   strcat(str1, "Host: www.baidu.com\n");
   strcat(str1, "Content-Type: text/html\n");
   strcat(str1, "Content-Length: ");
   strcat(str1, str);
   //请求空行
   strcat(str1, "\n\n");
   //请求参数
   strcat(str1, str2);
   strcat(str1, "\r\n\r\n");
   printf("%s\n",str1);

   ret = write(sockfd,str1,strlen(str1));
   if (ret < 0) {
       printf("socket write failed! errcode%d,errmsg'%s'\n",errno, strerror(errno));
       exit(0);
   }else{
       printf("socket write %d bytes!\n\n", ret);
   }

   FD_ZERO(&t_set1);
   FD_SET(sockfd, &t_set1);

   while(1) {
       sleep(2);
       h = 0;
       h = select(sockfd +1, &t_set1, NULL, NULL, &tv);
       if (h < 0) {
           close(sockfd);
           printf("SELECT error, return -1!\n");
           return -1;
       };

       if (h > 0){
           memset(buf, 0, BUF_SIZE);
           i= read(sockfd, buf, BUF_SIZE);
           if (i==0){
               close(sockfd);
               printf("read 0, return -1!\n");
               return -1;
           }

           printf("%s\n", buf);
       }
   }
   close(sockfd);
   return 0;
   ```
4. **httppost**
   ```
   int sockfd, ret, i, h;
   struct sockaddr_in servaddr;
   char str1[BUF_SIZE], str2[BUF_SIZE], buf[BUF_SIZE], *str;
   socklen_t len;
   fd_set   t_set1;
   struct timeval  tv;

   if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
       printf("create sockt failed---exit(0)!\n");
       exit(0);
   };

   bzero(&servaddr, sizeof(servaddr));
   servaddr.sin_family = AF_INET;
   servaddr.sin_port = htons(PORT);
   if (inet_pton(AF_INET, IPSTR_POST, &servaddr.sin_addr) <= 0 ){
       printf("inet_pton failed---exit(0)!\n");
       exit(0);
   };

   if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){
       printf("connect server failed, exit(0)!\n");
       exit(0);
   }
   printf("connect to server\n");

   memset(str2, 0, BUF_SIZE);
   strcat(str2, "keyword=&streetId=&pageNum=1&pageSize=1&ip=222.95.30.84");
   str=(char *)malloc(BUF_SIZE);
   len = strlen(str2);
   sprintf(str, "%d", len);
   //请求头部内容
   memset(str1, 0, BUF_SIZE);
   strcat(str1, "POST /qhhsd/app/getH5HsdList HTTP/1.1\n");
   strcat(str1, "Host: cysz.hopethink.com\n");
   strcat(str1, "Content-Type: application/x-www-form-urlencoded\n");
   strcat(str1, "Content-Length: ");
   strcat(str1, str);
   //请求空行
   strcat(str1, "\n\n");
   //str2的值为post的数据
   strcat(str1, str2);
   strcat(str1, "\r\n\r\n");
   printf("%s\n",str1);

   ret = write(sockfd,str1,strlen(str1));
   if (ret < 0) {
       printf("socket write failed! errcode%d, errmsg'%s'\n",errno, strerror(errno));
       exit(0);
   }else{
       printf("socket write %d bytes\n\n", ret);
   }

   FD_ZERO(&t_set1);
   FD_SET(sockfd, &t_set1);

   tv.tv_sec= 0;
   tv.tv_usec= 0;
   h= 0;

   while(1) {
       sleep(2);
       h = select(sockfd +1, &t_set1, NULL, NULL, &tv);
       if (h == -1) {
           close(sockfd);
           printf("select error, return -1\n");
           return -1;
       };
       if ( FD_ISSET(sockfd, &t_set1) ){
           memset(buf, 0, BUF_SIZE);
           i= read(sockfd, buf, BUF_SIZE);
           if (i==0){
               close(sockfd);
               printf("read 0, return -1!\n");
               return -1;
           }
           printf("%s\n", buf);
       }
   }
   close(sockfd);
   return 0;
   ```
5. **在main里增加方法和头文件**
   * **头文件**
     ```

     #include <stdio.h>
     #include <sys/socket.h>
     #include <sys/types.h>
     #include <time.h>
     #include <errno.h>
     #include <signal.h>
     #include <stdlib.h>
     #include <string.h>
     #include <unistd.h>
     #include <sys/wait.h>
     #include <sys/time.h>
     #include <netinet/in.h>
     #include <arpa/inet.h>

     #define IPSTR_GET "180.101.49.14" //服务器IP地址,上面查出来的;
     #define IPSTR_POST "114.215.124.251"

     #define PORT 80
     #define BUF_SIZE 4096
     ```
   * **方法**
     ```
     httpget();
     httppost();
     ```
6. **测试结果**
   1. **Get测试结果**

      ![image.png](https://forums-obs.openharmony.c ... moetqqpmsfupz91.png "image.png")
   2. **Post测试结果**

      ![image.png](https://forums-obs.openharmony.c ... ws5b6eskg3fgebl.png "image.png")

#### 总结

1. **http是建立在socket之上的数据结构化应用协议,可以通过拼socket包实现所有功能;**
2. **之后我们可以利用此接口实现一个核算地图的界面应用;**

**参考链接:**

[https://gitee.com/bearpi/bearpi-hm\_micro\_app/blob/master/README.md](https://gitee.com/bearpi/bearpi- ... ob/master/README.md)
[/md]




欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/) Powered by Discuz! X3.5