讓程式跨進網路時代——使用C語言擷取百度原始碼

來源:互聯網
上載者:User

  當我在單機世界摸爬滾打數月時,我也跟著時代的潮流,正式的跨入了網路化編程時代。學習一項新技術,永遠是一件令人興奮的事情。但是,想要找到一個好的學習教程無疑是一件困難的事情,搜尋百度Google無數次,終於踏入了Winsock的大門,我會在學習Windows網路編程中的心得體會發布出來,供大家學習。因為我也是新手,如果在博文當中有什麼錯誤的地方,還請各位高手大大提出來,以協助本人改正錯誤。

  如果你原來學習過Winsock編程,那麼看本篇文章將會非常輕鬆。如果沒學過,也沒關係,本篇博文將會詳細講解。OK,廢話不多說,直接跳到主題。

 

  1.在我們使用任何winsock函數之前,必須要現在標頭檔中添加winsock2.h和ws2_32.lib檔案。

#include <winsock2.h>#pragma comment(lib, "ws2_32.lib")

同時,我們要注意:winsock2.h標頭檔必須要放在windows.h標頭檔的上面,要不然編譯的時候會出錯。

  2.在我們調用任何winsock函數之前,還要必須通過WSAStartup函數完成對winsock服務的初始化。

int WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData )

(1)wVersionRequested:一個WORD(雙位元組)型數值,在最高版本的Windows Sockets支援調用者使用,高階位元組指定小版本(修訂本)號,低位位元組指定主要版本號。一般使用MAKEWORD(2,2)

(2)lpWSAData 指向WSADATA資料結構的指標,用來接收Windows Sockets實現的細節。

  3.當我們調用了WSAStartup函數後,便可以調用其他的winsock函數了。使用WSASocket函數建立一個與指定服務提供者捆綁的通訊端。

WSASocket(int af, int type, int protocol, LPWSAPROTOCOL_INFOW lpProtocolInfo, GROUP g, DWORD dwFlags);

(1)af:一個地址族規範,我們使用AF_INET。

(2)type:新通訊端的類型描述,我們使用SOCK_STREAM,也就是使用TCP

(3)protocol:通訊端使用的特定協議,如果調用者不願指定協議則定為0

(4)lpProtocolInfo:一個指向PROTOCOL_INFO結構的指標,該結構定義所建立套介面的特性。如果本參數非零,則前三個參數(af, type, protocol)被忽略。

(5)g:保留給未來使用的通訊端組。套介面組的標識符。

(6)dwFlags:套介面屬性描述。

一般我們都是用前面三個,後面的都為NULL。如果成功,返回的是一個SOCKET類型的通訊端。如果返回失敗,則返回SOCKET_ERROR

  4.我們使用connect函數串連上我們指定的網站。

connect(SOCKET s, const struct sockaddr FAR * name, int namelen);

(1)s:通訊端描述符,也就是我們調用的WSASocket函數返回的通訊端

(2)name:一個SOCKADDR類型,不過我們一般使用SOCKADDR_IN類型,也就是是我們需要串連的IP,連接埠等等

(3)namelen:SOCKADDR結構體的長度。

SOCKADDR_IN ipconfig;HOSTENT * iphost;char * url = "baidu.com";if((iphost = gethostbyname(url)) != NULL)    ipconfig.sin_addr.S_un.S_addr = inet_addr(inet_ntoa(*((struct in_addr *)iphost->h_addr_list[0])))ipconfig.sin_port = htons(80);ipconfig.sin_family = AF_INET;

可以看我的另外一篇博文:使用C語言擷取指定網域名稱的IP

 

  5.當我們串連以後,就需要發送http協議頭資訊了,如下:

char * httpHeader = "GET /index.html\r\nAccept: application/javascript, */*;q=0.8\r\nHost: baidu.com\r\nConnection: Keep-Alive\r\n\r\n"

然後使用send函數將其發送給主機。

send(sock, httpHeader, strlen(httpHeader) + 1, 0)

  6.如果我們發送出去以後,需要使用recv函數進行接收從伺服器返回過來的資訊,其中,第一次返回的是伺服器返回過來的HTTP頭,我們可以從中看見是否成功,其後返回過來的則是網頁的原始碼:

int i = 0, check, err = 0;char recvChar[100];char recvCDa[500];if(recv(sock, recvCDa, 500, 0) == SOCKET_ERROR)    {        fprintf(stderr, "返回資訊失敗,錯誤碼:%d",WSAGetLastError());        system("pause");        return 1;    }     printf("伺服器返回HTTP頭:%s\n", recvCDa);     memset(recvChar, '\0', 101);     while((check = recv(sock, recvChar, sizeof(recvChar), 0)) != SOCKET_ERROR)    {        if(check < 100)            err = 1;        printf("%s", recvChar);        memset(recvChar, 0, 100);        if(err == 1)            break;        i++;    }

OK,下面附上一段整體的擷取百度原始碼的代碼:

#include <stdio.h>#include <string.h>#include <winsock2.h>#include <Windows.h>#pragma comment(lib, "ws2_32.lib")using namespace std;char * urlIp(char * url);int main(int argc, char * argv[]){    SOCKADDR_IN url_ipconfig = {sizeof(SOCKADDR_IN)};    char * sendChar;    WSADATA wsaDa;    SOCKET sock;    char ip[20];    char sendString[100];    char recvChar[100];     char recvCDa[500];    if(WSAStartup(MAKEWORD(2,2), &wsaDa) == SOCKET_ERROR)    {        fprintf(stderr, "初始化WSAStartup出錯,錯誤碼:%d",WSAGetLastError());        system("pause");        return 1;    }    if((sock = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, NULL, 0)) == SOCKET_ERROR)    {        fprintf(stderr, "初始化WSAStartup出錯,錯誤碼:%d",WSAGetLastError());        system("pause");        return 1;    }        strcpy(ip, urlIp("baidu.com"));    url_ipconfig.sin_family = AF_INET;    url_ipconfig.sin_port = htons(80);    url_ipconfig.sin_addr.S_un.S_addr = inet_addr(ip);    if(connect(sock, (SOCKADDR *)&url_ipconfig, sizeof(url_ipconfig)) == SOCKET_ERROR)    {        fprintf(stderr, "串連伺服器失敗,錯誤碼:%d",WSAGetLastError());        system("pause");        return 1;    }    strcpy(sendString, "GET /index.html HTTP/1.1\r\nAccept: application/javascript, */*;q=0.8\r\nHost: baidu.com\r\nConnection: Keep-Alive\r\n\r\n");    if(send(sock, sendString, strlen(sendString) + 1, 0) == SOCKET_ERROR)    {        fprintf(stderr, "發送GET包失敗失敗,錯誤碼:%d\n",WSAGetLastError());        system("pause");        return 1;    }     memset(recvCDa, '\0', 500);     if(recv(sock, recvCDa, 500, 0) == SOCKET_ERROR)    {        fprintf(stderr, "返回資訊失敗,錯誤碼:%d",WSAGetLastError());        system("pause");        return 1;    }     printf("%s\n", recvCDa);     int i = 0, check, err = 0;     memset(recvChar, '\0', 101);     while((check = recv(sock, recvChar, sizeof(recvChar), 0)) != SOCKET_ERROR)    {        if(check < 100)            err = 1;        printf("%s", recvChar);        memset(recvChar, 0, 100);        if(err == 1)            break;        i++;    }    system("pause");    return 0;}char * urlIp(char * url){    HOSTENT * iphost;    char ipconfig[20];    char ip[20];    if((iphost = gethostbyname(url)) != NULL)    {        memcpy(&ip, inet_ntoa(*((struct in_addr *)iphost->h_addr_list[0])), 20);    }    return ip;}

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.