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》。