如何利用
socket
進行
HTTP
訪問平常我們要訪問某個URL一般都是通過瀏覽器進行:提交一個URL請求後,瀏覽器將請求發向目標伺服器或者Proxy 伺服器,目標伺服器或者Proxy 伺服器返回我們所需要的資料,瀏覽器接收到這些資料後儲存成檔案並進行顯示。下面我們看看如何自己利用winsock2.h中的介面來實現這個功能?為了簡化問題,作以下假設:通過Proxy 伺服器進行HTTP訪問,這樣就省去了對URL進行DNS解析的步驟,假設Proxy 伺服器的地址為:192.168.0.1:808。 這個功能由以下幾個部分組成:1. 如何建立串連?2. 如何發送請求?3. 如何接收資料?4. 如何判斷資料接收完成? 下面我們依次來看下這些問題如何解決?
一、
如何建立與伺服器之間的串連HTTP基本TCP,所以我們需要與伺服器建立串連,然後才能發送資料。建立串連參考如下函數socket_open:/**開啟Socket,返回socketId,-1表示失敗*/int socket_open(int IP,int Port,int type){SOCKET socketId; struct sockaddr_in serv_addr; int status; socketId=socket(AF_INET,SOCK_STREAM,0); if((int)socketId<0) { printf("[ERROR]Create a socket failed!/n"); return -1; } memset(&serv_addr,0,sizeof(serv_addr)); serv_addr.sin_family=AF_INET; serv_addr.sin_addr.s_addr = ntohl(IP); serv_addr.sin_port = htons((USHORT)Port); status=connect(socketId,(struct sockaddr*)&serv_addr,sizeof(serv_addr)); if(status!=0) { printf("[ERROR]Connecting failed!/n"); closesocket(socketId); return -1; } return socketId;} 調用方式如下:int socketId=socket_open(0xC0A80001,808,0); //0xC0A80001是192.168.0.1的十六進位寫法。
二、
如何發送請求發送資料要根據HTTP協議的要求附加協議頭:static const char* protocolHead="GET http://www.xxx.com/index.html HTTP/1.1/n" "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*/n" "Accept-Language: zh-cn/n" "User-Agent:iPanelBrowser/2.0/n" "Host: www.xxx.com:80/n" "Connection: close/n/n" 這裡使用GET來擷取指定URL的指定文檔。 建立串連後使用send將這些資料發送出去: send(socketId, protocolHead,strlen(protocolHead),0); 發送完成HTTP請求後就等待接收資料。
三、
如何接收資料這裡採用select迴圈查詢的方式來判斷有無資料到來: struct timeval tm = {0,7}; fd_set fds_r; int status; char recvBuf[4096]={‘/0’}; FD_ZERO(&fds_r); FD_SET(socketId,&fds_r); status=select(socketId+ 1, &fds_r, 0, 0, &tm); //socketId在這裡是最大的fd if(status > 0 && FD_ISSET(socketId, &fds_r)){ printf("Socket is readable...fd=[%d]/n",socketId); recv(socketId,recvBuf,4096,0);} 這樣資料包就儲存到緩衝區中了。
四、
如何判斷資料接收完成首先對返回資料的狀態進行判斷,僅當狀態為“ HTTP 200 OK ”時才表明正確返回,這時才對資料進行解析並儲存,如果狀態為HTTP 404 NOT FOUND或者其它狀態則表明沒有找到資源或者出現其它問題,可參考
HTTP 1.1狀態碼及其含義。當資料正確返回時,為了將實際資料從協議中分離出來進行儲存,需要對HTTP資料包進行解析得到Content-Length,然後在包含Content-Length的當前資料包或者隨後的資料包中尋找第一個空行,這就是內容(Content)的開始位置,再配合前面解析得到的Content-Length,就能夠知道什麼時候資料接收完成了。分行符號為“/r/n”,也相容“/n”或者“/r”,設分行符號為^P,則空行如果位於內容中間或結尾則可尋找“^P^P”,若位於開頭,則尋找^P。 基本就是上面這些,這四個問題解決了,那麼整個問題也就解決了!