天天看點

#沖刺創作新星# #跟着小白一起學鴻蒙# [十二]簡單Http用戶端

作者:王石

在《#跟着小白一起學鴻蒙# [二] 第一個OpenHarmony程式》我們熟悉了如何在開源鴻蒙開發應用,并通過hdc工具拷貝至開發闆運作。但是那時候我們隻是列印了最簡單的hello world,接下來我們就講開發最常用的部分,一個簡單的http用戶端;

概述

  • 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

  • 請求資料結構如下
#沖刺創作新星# #跟着小白一起學鴻蒙# [十二]簡單Http用戶端
  • 一個Get的sample

在浏覽器輸入www.baidu.com然後回車即可看到浏覽器顯示了百度的頁面,按F12可以看到具體内容:

#沖刺創作新星# #跟着小白一起學鴻蒙# [十二]簡單Http用戶端

上圖裡我們可以看到在請求的url是www.baidu.com,請求的方法是GET,伺服器的IP位址是180.101.49.14:443(https,若是http就是80)

  • 一個Post的sample
    #沖刺創作新星# #跟着小白一起學鴻蒙# [十二]簡單Http用戶端
    上圖裡我們可以看到在請求的url是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,請求資料keyword=&streetId=&pageNum=1&pageSize=1&ip=222.95.30.84

此樣例參考小熊派設計,使用小熊派HM_Micro開發闆進行驗證

應用開發流程

graph LR
建立build.gn --> 建立helloworld.c --> 添加httpget --> 添加httppost --> 驗證
           
  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測試結果
      #沖刺創作新星# #跟着小白一起學鴻蒙# [十二]簡單Http用戶端
    2. Post測試結果
      #沖刺創作新星# #跟着小白一起學鴻蒙# [十二]簡單Http用戶端

總結

  1. http是建立在socket之上的資料結構化應用協定,可以通過拼socket包實作所有功能;
  2. 之後我們可以利用此接口實作一個核算地圖的界面應用;

參考連結:

https://gitee.com/bearpi/bearpi-hm_micro_app/blob/master/README.md

本文作者:左翼風發

繼續閱讀