HTTPCLIENT源碼分析

HTTPCLIENT源碼分析

—mt7686 httpclient模塊

http是應用層的協議,在傳輸層使用tcp協議,可以從其源碼分析,中間層就是調用socket(基於lwip協議)編程加上http協議實現,下面看源碼。想看看其源碼的可以從下面目錄下載。
下載目錄:點擊這裏
路徑在middleware/third_party/httpclient中。

源碼分析
以前已經介紹過httpclient api的使用了,此處不在贅述,本文主要介紹下面代碼的中間層實現。

static HTTPCLIENT_RESULT httpclient_common(httpclient_t *client, char *url, int method, httpclient_data_t *client_data)
{
    HTTPCLIENT_RESULT ret = HTTPCLIENT_ERROR_CONN;

    ret = httpclient_connect(client, url);

    if (!ret) {
        ret = httpclient_send_request(client, url, method, client_data);

        if (!ret) {
            ret = httpclient_recv_response(client, client_data);
        }
    }

    httpclient_close(client);

    return ret;
}

1.httpclient_connect函數

創建tcp連接過程,此處貼出主要代碼。

	//解析url,確認目的地址
	httpclient_parse_url(url, scheme, sizeof(scheme), host, sizeof(host), &(client->remote_port), path, HTTPCLIENT_MAX_URL_LEN);
	//檢查http or https後,確認端口
 	   if (client->remote_port == 0) {
   	     if (client->is_http) {
      	      client->remote_port = HTTP_PORT;
    	    } else {
    	        client->remote_port = HTTPS_PORT;
   	     }
  	  }
     //以tcp,創建tcp連接
        if (client->is_http)
    	    ret = httpclient_conn(client, host);
     //分析httpclient_conn;創建套接字,填充地址結構,連接
     //填充地址結構
 	   memset( &hints, 0, sizeof( hints ) );
 	   hints.ai_family = AF_UNSPEC;
  	  hints.ai_socktype = SOCK_STREAM;
  	  hints.ai_protocol = IPPROTO_TCP;
	  snprintf(port, sizeof(port), "%d", client->remote_port) ;
  	  if ( getaddrinfo( host, port , &hints, &addr_list ) != 0 ) {
     	   DBG("getaddrinfo != 0, return HTTPCLIENT_UNRESOLVED_DNS");
      	  return HTTPCLIENT_UNRESOLVED_DNS;
  	  }
     //創建套接字
        client->socket = (int) socket( cur->ai_family, cur->ai_socktype,
                                        cur->ai_protocol );
	 //連接
		connect( client->socket, cur->ai_addr, (int)cur->ai_addrlen )

至此,函數如果正確返回,就創建tcp連接成功了,接下來就是發送接收數據了,最終應該調用的send(),recv()函數接口。

2.httpclient_send_request函數

瞭解這個函數接口,必須瞭解下http報文結構了,這裏以請求報文爲例。
在這裏插入圖片描述
發送http數據之前,都會先發送報文首部數據,然後再看這個函數實現。

HTTPCLIENT_RESULT httpclient_send_request(httpclient_t *client, char *url, int method, httpclient_data_t *client_data)
{
    int ret = HTTPCLIENT_ERROR_CONN;

    if (client->socket < 0) {
        return (HTTPCLIENT_RESULT)ret;
    }
//發送報文首部
    ret = httpclient_send_header(client, url, method, client_data);
    if (ret != 0) {
        return (HTTPCLIENT_RESULT)ret;
    }

    if (method == HTTPCLIENT_POST || method == HTTPCLIENT_PUT) {
    //發送用戶數據
        ret = httpclient_send_userdata(client, client_data);  
    }

    DBG("httpclient_send_request() result:%d, client:%p", ret, client);
    return (HTTPCLIENT_RESULT)ret;
}

HTTP 首部字段是構成 HTTP 報文的要素之一。在客戶端與服務器之
間以 HTTP 協議進行通信的過程中,無論是請求還是響應都會使用首
部字段,它能起到傳遞額外重要信息的作用。代碼實現不做解釋了。

注意:關於這個api,想發送數據,跟到函數最後肯定調用lwip協議棧中send函數。
如下,httpclient最終只要發送數據都會調用下面接口

 send(sock_fd, data + written_len, length - written_len, 0);

3.httpclient_recv_response函數

接收http響應的函數接口,同理,接收的也是一個響應報文,除了接收數據後,對接收的報文也需要解析,這就是這個函數的具體功能了。
響應報文如下:
在這裏插入圖片描述
接收數據:

httpclient_recv(client, data + len, 1, header_buf_len - len - 1, &new_trf_len);

最終調用lwip協議棧中的接口recv

recv(client->socket, buf + readLen, max_len - readLen, 0);

關於http請求與響應的報文首部,想詳細瞭解和學習的,可以取查閱《圖解http》。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章