程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++ socket網絡爬蟲(1)

C++ socket網絡爬蟲(1)

編輯:C++入門知識

C++寫的socket網絡爬蟲,代碼會在最後一次講解中提供給大家,同時我也會在寫的同時不斷的對代碼進行完善與修改

 

我首先向大家講解如何將網頁中的內容,文本,圖片等下載到電腦中。

一、main函數

1、makeSocket(url,port)

int makeSocket(string host,int port)函數是我自己編寫的,接受兩個參數,一個是域名或主機名,第二個是所使用的端口號,返回一個用於創建socket的int型數據,將在這一頁的二.makeSocket中進行講解

 

2、string request = "GET " + name + " HTTP/1.1\r\nHost:" + url + "\r\nConnection:Close\r\n\r\n";

這個是http的請求報頭,有很多的信息,這裡只對這句話中使用到的進行講解

GET 請求獲取Request-URI所標識的資源;

 

name 所標識的資源;

 

HTTP/1.1 表示請求的HTTP協議版本;

 

Host:url  指定被請求資源的Internet主機和端口號,通常從HTTP URL中提取出來的,

比如 我們在浏覽器中輸入http://baidu.com/index.html浏覽器發送的請求消息中,就會包含Host請求報頭域,如下:
Host:www.baidu.com

此處使用缺省端口號80,若指定了端口號,則變成:Host:www.baidu.com:port

 

Connection:Close Connection字段用於設定是否使用長連接,在http1.1中默認是使用長連接的,即Connection的值為Keep-alive,如果不想使用長連接則需要明確指出connection的值為close

Connection:Close表明當前正在使用的tcp鏈接在請求處理完畢後會被斷掉。以後client再進行新的請求時就必須創建新的tcp鏈接了,即必須從新創建socket

更多關於http協議的內容可以查考http://blog.csdn.net/gueter/article/details/1524447   HTTP協議詳解

 

注意最後一定要以一個單獨的\r\n作為結束標志

 

3.send/recv

send用於向服務端發送消息

recv/send函數原型如下

int recv(SOCKET s,char FAR * buf,int len,int flags)/int send(SOCKET s,const char FAR * buf,int len,int flags);

第一個參數表示代表對方的socket,

第二個參數為接收讀取的信息的字符串

第三個參數為該字符串的大小

第四個參數可以用來控制讀寫操作

詳情可以參照http://www.cnblogs.com/magicsoar/p/3587351.html 中的講解1

 

4 FileName(name)

自己編寫的string FileName(string dir)函數,由於windows中文件的名字中不允許含有/

所以FileName函數用於將dir中的所有/替換為_

 FileName( search =  pos =  ((pos = dir.find(search, pos)) != ++

如string FileName(“img/bdlogo.gif”)返回_img_bdlogo.gif

 

5 file.open(fileName, ios::out | ios::binary)r45

ios::out以輸出方式打開文件,如果文件不存在這創建新的文件

ios::binary以二進制模式進行I/O操作,這裡使用二進制模式是為了正確的處理圖片的下載

 

6 ::memset(buf, 0, sizeof(buf));

函數原型為void *memset(void *s, int ch, size n);

函數解釋:將s所指的內存中前n個字節 (typedef unsigned int size_t)用 ch 替換並返回 s 。

memset:作用是在一段內存塊中填充某個給定的值,它是對較大的結構體和數組進行清零操作的一種較快方法

 

7 在接收和解釋請求消息後,服務器返回一個HTTP響應消息。

HTTP響應也是由三個部分組成,分別是:狀態行、消息報頭、響應正文

響應正文就是服務器返回的資源的內容,所以我們需要跳過狀態行與消息報頭部分。

消息報頭與相應正文之間可以用\r\n\r\n進行區分,當第一次發現接收到的字符串數組中含有\r\n\r\n時,則將\r\n\r\n前的內容全部忽略,將剩下的內容寫到文件中去

 

strstr(*str1, *str2)實現從字符串str1中查找是否有字符串str2,如果有,從str1中的str2位置起,返回str1中str2起始位置的指針,如果沒有,返回null。

由於一次最多可以接受1024個字符,而\r\n極有可能位於中間位置,所有我們要將1024個char中位於\r\n之後的數據寫到文件中。

 

二.makeSocket函數

 

 makeSocket( host,
    WSAStartup(MAKEWORD(, ), &inet_WsaData);
     (LOBYTE(inet_WsaData.wVersion) !=  || HIBYTE(inet_WsaData.wVersion) != )
 - tcp_socket = socket(AF_INET, SOCK_STREAM, );
     hostent * hp = ::gethostbyname(host.c_str());
    ==&saddr.sin_addr, hp->h_addr,  (connect(tcp_socket, (  sockaddr *)&saddr, (saddr)) == -)
<<  <<

1 見http://www.cnblogs.com/magicsoar/p/3585129.html windows下的C++ socket服務器(3)中講解

2 struct hostent * hp = ::gethostbyname(host.c_str());

gethostbyname()返回對應於給定主機名的包含主機名字和地址信息的hostent結構指針

 

hostent結構體的定義如下

struct  hostent {
        char    FAR * h_name;           /* official name of host */
        char    FAR * FAR * h_aliases;  /* alias list */
        short   h_addrtype;             /* host address type */
        short   h_length;               /* length of address */
        char    FAR * FAR * h_addr_list; /* list of addresses */
#define h_addr  h_addr_list[0]          /* address, for backward compat */
};

hostent->h_name表示的是主機的規范名。例如的規范名其實是www.a.shifen.com。(關於www.a.shifen.com還有一段故事http://www.zhihu.com/question/20100901)
hostent->h_aliases表示的是主機的別名.www.google.com就是google他自己的別名。有的時候,有的主機可能有好幾個別名,這些,其實都是為了易於用戶記憶而為自己的網站多取的名字。
hostent->h_addrtype表示的是主機ip地址的類型,到底是ipv4(AF_INET),還是pv6(AF_INET6)
hostent->h_length表示的是主機ip地址的長度

hostent->h_addr_list表示的是主機的ip地址

#define h_addr h_addr_list[0]

 

3 memcpy(&saddr.sin_addr, hp->h_addr, 4);

由於 hp->h_addr是char*類型,不能直接賦值給saddr.sin_addr

所以我們使用了memcpy函數

函數原型如下

void *memcpy(void *dest, const void *src, size_t n);

從源src所指的內存地址的起始位置開始拷貝n個字節到目標dest所指的內存地址的起始位置中。

 

程序的下載地址

http://files.cnblogs.com/magicsoar/Webcrawler1.rar

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved