前些天完成一個小項目蒲讯,其主要功能是通過C++編程發(fā)起http請求劫映,并對通訊信息加密。其中難點在于對方是java服務(wù)器嗤攻,交換數(shù)據(jù)信息需要嚴格按照某種數(shù)據(jù)交換格式如json,xml等來定義诽俯。期間使用了一個第三方庫ghttp妇菱,下面我們主要來分析ghttp源碼來了解整個http請求的過程。
第一步:解析域名通過域名獲取對應(yīng)請求的主機或服務(wù)器的ip和端口暴区。
第二步:通過socket編程向上述主機或服務(wù)器的ip和端口建立連接闯团。
第三步:把請求內(nèi)容按照http協(xié)議來進行組裝
第四步:將封裝好的http協(xié)議內(nèi)容發(fā)送到目的服務(wù)器
第五步:接收服務(wù)器反饋內(nèi)容
htpp協(xié)議與鏈接地址的全部內(nèi)容_ghttp_request結(jié)構(gòu)體
<pre>
<code>struct _ghttp_request</code>
{
http_uri *uri;
http_uri *proxy;
http_req *req;
http_resp *resp;
http_trans_conn *conn;
const char *errstr;
int connected;
ghttp_proc proc;
char *username;
char *password;
char *authtoken;
char *proxy_username;
char *proxy_password;
char *proxy_authtoken;
};
</pre>
*** 1.在ghttp中與建立連接相關(guān)的數(shù)據(jù)結(jié)構(gòu)和函數(shù)定義 ***
1.1 http_uri是對請求URL對象的解析
<pre>
typedef struct http_uri_tag
{
char full; / full URL */
char proto; / protocol */
char host; / copy semantics */
unsigned short port;
char resource; / copy semantics */
} http_uri;
</pre>
1.2 http_trans_conn是對信息發(fā)送對象的封裝
<pre>typedef struct http_trans_conn_tag {
struct hostent *hostinfo;
struct sockaddr_in saddr;
char *host;
char proxy_host;
int sock;
short port;
short proxy_port;
http_trans_err_type error_type;
int error;
int sync; / sync or async? */
char io_buf; / buffer /
int io_buf_len; / how big is it? /
int io_buf_alloc; / how much is used /
int io_buf_io_done; / how much have we already moved? /
int io_buf_io_left; / how much data do we have left? /
int io_buf_chunksize; / how big should the chunks be that get
read in and out be? /
int last_read; / the size of the last read /
int chunk_len; / length of a chunk. */
char errstr; / a hint as to an error */
} http_trans_conn;
</pre>
通過對URL的解析將必要的連接目標信息裝入http_uri對象。然后從http_uri對象中取出host和port保存到http_trans_conn對象颜启。http_trans_conn不僅保存目的服務(wù)器的IP與端口信息還定義了發(fā)送和接收緩存以及同步異步方式偷俭。
1.3 信息交換的三大函數(shù)
<pre>int http_trans_connect(http_trans_conn *a_conn)</pre>
通過向http_trans_conn指定的host和port發(fā)起連接,其中使用gethostbyname(a_conn->host)來獲取指定主機的真實ip地址。通過socket方式建立連接。
<pre>int http_req_send(a_request->req, a_request->conn)
</pre>
向連接的目的地發(fā)送數(shù)據(jù)泵三,實現(xiàn)函數(shù)write();
<pre>
int http_resp_read_headers(a_request->resp, a_request->conn)
int http_resp_read_body(a_request->resp,a_request->req,a_request->conn)
</pre>
*從連接通道中讀取數(shù)據(jù),實現(xiàn)函數(shù)read();
*** 2 在ghttp中對http協(xié)議的封裝 ***
2.1 請求報文
<pre>typedef struct http_req_tag {
http_req_type type;
float http_ver;
char *host;
char *full_uri;
char *resource;
char *body;
int body_len;
http_hdr_list *headers;
http_req_state state;
} http_req;
</pre>
下面以post方法為例加上一個標準的請求報文來分析這個結(jié)構(gòu)體负溪。該請求報文的請求方法為post保存在http_req_type type類型的type里。協(xié)議版本號HTTP/1.1保存在http_ver里济炎。/search保存在resource屬性里面川抡。
<pre>POST /search HTTP/1.1</pre>
host保存到char *host屬性中。
<pre>
Host: <a >www.google.cn</a>
</pre>
下面此段都為頭部屬性以鍵值對列的形式存儲在
http_hdr_list *headers中须尚。
<pre>
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint,
application/msword, application/x-silverlight, application/x-shockwave-flash, /
Referer: <a >http://www.google.cn/</a>
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; TheWorld)
Connection: Keep-Alive
Cookie: PREF=ID=80a06da87be9ae3c:U=f7167333e2c3b714:NW=1:TM=1261551909:LM=1261551917:S=ybYcq2wpfefs4V9g;
NID=31=ojj8d-IygaEtSxLgaJmqSjVhCspkviJrB6omjamNrSm8lZhKy_yMf
O2M4QMRKcH1g0iQv9u-2hfBW7bUFwVh7pGaRUb0RnHcJU37y-
FxlRugatx63JLv7CWMD6UB_O_r
</pre>
在發(fā)送前http_req結(jié)構(gòu)體中報文的各種信息按照http協(xié)議標準格式定義來封裝崖堤,存入http_trans_conn結(jié)構(gòu)體中的io_buf中。然后通過write方法發(fā)送耐床。
2.2 響應(yīng)報文
通過read函數(shù)讀取接收到的數(shù)據(jù)保存到http_trans_conn中的io_buf中并由io_buf_alloc指定其在io_buf中的位置密幔。然后通過
<pre>
int http_resp_read_headers(http_resp *a_resp, http_trans_conn *a_conn)
int http_resp_read_body(http_resp *a_resp,http_req *a_req,http_trans_conn *a_conn)
</pre>
倆函數(shù)來將io_buf中的內(nèi)容解析到http_resp結(jié)構(gòu)體中。
<pre>typedef struct http_resp_tag
{
float http_ver;
int status_code;
char *reason_phrase;
http_hdr_list *headers;
char *body;
int body_len;
int content_length;
int flushed_length;
http_resp_header_state header_state;
http_resp_body_state body_state;
} http_resp;
</pre>
通過本文撩轰,我們可以看到協(xié)議即語境胯甩,不管你是哪國人,中國人堪嫂,美國人或者日本人偎箫,只要你使用相同的語境(英語或者其他語言)交流大家都能實現(xiàn)基本的溝通。不同平臺也是不管你是C++實現(xiàn)或者java皆串,只要嚴格按照遵守http協(xié)議規(guī)定都能實現(xiàn)有效的信息交換淹办。