#include "stdafx.h"
#include <winsock.h> //相关的头文件
#include <iostream>
#pragma comment(lib,"ws2_32.lib")//VS下winsock编程一定要加这句话 不然会出错
using namespace std;
int UrlSnap(char* URL,char* &pageBuf)//自定义的抓取网页的函数,这里第二个参数使用了&引用类型,类似于delphi中的var 修饰
{
WSADATA wsa;
if(WSAStartup(0x101,&wsa)!=0)
{MessageBox(0,TEXT("Load winsock Failed"),TEXT("Erro"),MB_OK);}
//在vs编译器中对需要使用unicode宽字符的地方都要用TEXT宏,如果要输 出显示宽字符,可以使用wcout<<来输出,或者使用printf("%ws",string),用%ws进行输出格式控制
char request[512]="GET / HTTP/1.0\r\nHost: ";
strcat_s(request,URL);
strcat_s(request,"\r\nConnection: Close\r\n\r\n");
// 字符串操作的一系列函数:strcmp,strcat,strlen因为不够安全都已经停止使用,而改用其安全类型的strcat_s,strcmp_s,strlen_s等,对于宽字符则使用lstrcat,lstrcmp,lstrlen等
struct hostent* ph=gethostbyname(URL);
if(ph==NULL)
{MessageBox(0,TEXT(" Failed in gethostbyname"),TEXT("Erro"),MB_OK);}
struct in_addr inAddr;
LPSTR lpaddr=ph->h_addr;//获取的地址是网络字节顺序
memmove(&inAddr,lpaddr,4); // 将获取的地址移动4个字节到inAddr结构中
int sock, ret = 0, optval = 1;
struct sockaddr_in sa;
sa.sin_family = AF_INET; //用于指定地址格式
sa.sin_port = htons(80); //指定端口,这里htons将80转化为网络字节顺序
sa.sin_addr.s_addr = inet_addr(inet_ntoa(inAddr));
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
connect(sock, (SOCKADDR*)&sa, sizeof(sa));
if(sock == -1)
{
return(1);
}
if(sock == -2)
{
return(1);
}
ret = send(sock, request, strlen(request), 0);
int m_nContentLength =1048576 ;
pageBuf = (char *)malloc(m_nContentLength);
memset(pageBuf, 0, m_nContentLength);
int bytesRead = 0;
while(ret > 0)
{
ret = recv(sock, pageBuf + bytesRead, m_nContentLength - bytesRead, 0);
if(ret > 0)
{
bytesRead += ret;
}
}
pageBuf[bytesRead] = '\0';
WSACleanup();
return(0);
}
int _tmain(int argc, _TCHAR* argv[])
{
char* URLcontent;
UrlSnap("www.hao123.com",URLcontent);
cout<<URLcontent;
system("pause");
return 0;
}
这中间涉及到一点的winsock编程知识,通过gethostbyname来获取地址信息,该函数会返回一个 hostent*类型的指针,其中hostent结构如下
<pre class="cpp" name="code">typedef struct hostent {
char FAR* h_name;
char FAR FAR** h_aliases;
short h_addrtype;
short h_length;
char FAR FAR** h_addr_list; //h_addr被定义为该地址列表中的第一个地址,该地址是网络顺序的;
} HOSTENT, *PHOSTENT, FAR *LPHOSTENT;
inet_addr 该函数将一个由小数点分割的十进制IP地址字符串转换成由32位二进制数表示的ip地址(网络字节顺序)
inet_ntoa 该函数是inet_addr的逆函数,将网络顺序的32位IP地址转换成字符串
in_addr 该结构代表了一个ipv4的网络地址,其字节顺序为网络顺序