讓程序跨進網絡時代——使用C語言獲取百度源代碼


  當我在單機世界摸爬滾打數月時,我也跟着時代的潮流,正式的跨入了網絡化編程時代。學習一項新技術,永遠是一件令人興奮的事情。但是,想要找到一個好的學習教程無疑是一件困難的事情,搜尋百度谷歌無數次,終於踏入了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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM