Winsocke简述、取网页原理概述

来源:互联网 发布:linux alias ll 编辑:程序博客网 时间:2024/06/14 00:27

偶身为IT行业中的程序猿小白对于Winsocket网络编程只是略知一二,并没有深入研究,编写代码的水平也只是停留在通过网络套接字实现简单的通信,比如Server和Client之间的通信之类的(Chartroom、FTP)。前些日子,翠花学长问偶怎么用socket下载某网站(不植入广告~~)的主页,这引起偶的极大兴趣,因为之前有简单接触过python,通过其可快速实现网络爬虫中的网页下载功能,其实也只是简单的几行代码而已(小编脑残,记性不佳~~)。

首先一起简单回顾一下Winsocket的简单使用(windows下VS平台):

1、在头文件中包含winsocket2.h:有些童鞋可能会发现windows下有winsock.h和winsock2.h,winsock2.h是winsock.h的升级版,它设计的目的是替代winsock.h,而不是扩展它,因此在winsock.h中定义的所有内容在winsock2.h中也都定义了。此外,winsock2.h定义了_WINSOCKAPI_,阻止编译器去处理后面的winsock.h,这样编译不会报错。但是如果winsock.h在winsock2.h前出现,winsock2.h就重新定义winsock.h已经定义的东西,导致编译报错(亲测,可信~~)。


2、#pragma comment(lib,"ws2_32.lib") 如果没有添加这行代码的话,会出现很多和ws2def.h文件相关的错误,这是因为程序缺少相应的静态链接库,当然也可以手动链接,这里则需要根据不同的平台进行响应的操作。


3、socket环境的初始化

int WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData );

  1. wVersionRequested:一个WORD(双字节)型数值,在最高版本的Windows Sockets支持调用者使用,高阶字节指定小版本(修订本)号,低位字节指定主版本号。现在的版本应该是2.2
  2. lpWSAData 指向WSADATA数据结构的指针,用来接收Windows Sockets 实现的细节。


4、根据通信模型的设计,分为Server端和Client端

4.1、对于Server端

4.1.1、创建套接字socket

SOCKET PASCAL FAR socket( int af, int type, int protocol);

  1. af:一个地址描述。目前仅支持AF_INET格式,也就是说ARPA Internet地址格式。
  2. type:指定socket类型。新套接口的类型描述类型,如TCP(SOCK_STREAM)和UDP(SOCK_DGRAM)。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。
  3. protocol:顾名思义,就是指定协议。套接口所用的协议。如调用者不想指定,可用0。常用的协议有,IPPROTO_TCP、IPPROTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。
4.1.2、绑定Sever端地址
int bind(int sockfd, struct sockaddr * my_addr, int addrlen);
函数说明:bind()用来设置给参数sockfd 的socket 一个名称. 此名称由参数my_addr 指向一sockaddr 结构,对于不同的socket domain 定义了一个通用的数据结构
  1. sockfd:由socket()创建的要绑定地址的套接字ID
  2. my_addr:要绑定的地址(IP+Port)
  3. addrlen:要绑定地址的结构体大小
4.1.3、设置Server端进行监听
int listen(SOCKET sockfd, int backlog);
  1. sockfd:一个已绑定未被连接的套接字描述符
  2. backlog:连接请求队列(queue of pending connections)的最大长度(一般由2到4),如果用SOMAXCONN,则大小由系统确定。

4.1.4、Server端等待和接受连接请求
int accept(int sockfd, struct sockaddr* addr, socklen_t* len);
  1. sockfd:之前设置的监听套接字,这个套接字用来监听一个端口,当有一个客户与服务器连接时,它使用一个端口号,而此时这个端口号正与这个套接字关联。当然客户不知道套接字这些细节,它只知道一个地址和一个端口号。
  2. addr:这是一个结果参数,它用来接受一个返回值,这返回值指定客户端的地址,当然这个地址是通过某个地址结构来描述的,用户应该知道这一个什么样的地址结构。如果对客户的地址不感兴趣,那么可以把这个值设置为NULL。
  3. len:它也是结果的参数,用来接受上述addr的结构的大小的,它指明addr结构所占有的字节个数。同样的,它也可以被设置为NULL。
4.1.5、发送数据
int PASCAL FAR send( SOCKET s, const char FAR* buf, int len, int flags);
  1. s:一个用于标识已连接套接口的描述字。
  2. buf:包含待发送数据的缓冲区。
  3. len:缓冲区中数据的长度。
  4. flags:调用执行方式。通常设置为0。
int PASCAL FAR sendto( SOCKET s, const char FAR* buf, int len, int flags,  const struct sockaddr FAR* to, int tolen);
  1. s:一个标识套接口的描述字。
  2. buf:包含待发送数据的缓冲区。
  3. len:buf缓冲区中数据的长度。
  4. flags:调用方式标志位。
  5. to:(可选)指针,指向目的套接口的地址。
  6. tolen:to所指地址的长度。

4.1.6、接收数据
int recv( SOCKET s, char FAR *buf, int len, int flags );
  1. s:指定接收端套接字描述符;
  2. buf:指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;
  3. len:指明buf的长度;
  4. flags:调用方式标志位,一般置0。
size_t recvfrom(int sockfd,void *buf,int len,unsigned int flags, struct sockaddr *from,socket_t *fromlen);
  1. sockfd:标识一个已连接套接口的描述字。
  2. buf:接收数据缓冲区。
  3. len:缓冲区长度。
  4. flags:调用操作方式。
  5. from:(可选)指针,指向发送数据的套接口的地址。
  6. fromlenfrom所指地址的长度。

4.1.7、环境清理,终止Winsock 2 DLL (Ws2_32.dll) 的使用
int PASCAL FAR WSACleanup (void);

4.2.、Client端的设置
CLient端套接字的创建和地址的绑定和Server端的操作一样,数据的发送和接收也和Server的情况类似。不同的是,Client需要发起对Server端的连接请求。

 int PASCAL FAR connect( SOCKET s, const struct sockaddr FAR* name, int namelen);
  1. s:标识一个未连接套接口的描述字。
  2. name:欲进行连接的地址。
  3. namelen:名字长度。
连接成功后就可以进行正常的数据通信。
此后同样需要进行套接字的关闭和环境的清理终止Winsock 2 DLL (Ws2_32.dll) 的使用,这点和Server端的操作相同。

至此,我们简单复习了一下socket的网络编程过程。
接下来,我们简单说说关于网络爬虫的事情。网络爬虫能够通过实现对网页的自动获取和下载,本质上,可以说网络爬虫是浏览器的一个自动实现。
在刚接触Winsocket编程的时候,小编作为小白只晓得上述的简单通讯过程,曾经一度好奇如何通过Winsocket来获取网页页面,但由于能力有限,放弃深入研究。
通过这些天的简单探索,发现其实网络爬虫对于网页的获取大体上和上述的通信模型类似,无非就是Client端向服务器发起页面请求意图,Server端根据接收到的请求内容进行响应,返回响应的数据信息。上述过程听起来很简单,但是要意识到这点小编我着实花了不少时间来感悟(——!比较笨)。
问题在于Client需要发送什么消息才能够使Server理解并返回Client需要的数据信息,于是乎,Http协议闪亮登场~~
关于Http的种种,小白偷懒,直接提供借个传送门吧
Http协议详解

socket 发送http请求 参数详细说明

 HTTP请求头详解

因此,构造Http请求报文就成了网络爬虫获取页面的关键之处。
所以,只要能正确构造出Http请求报文,然后发送到指定服务器就可以顺利得到想要下载的网页内容。
至此,小编就不多废话,直接贴出小编的一个简短例子。

//这里是要发送的http头部
SendString(sock,"GET / HTTP/1.1\r\n");
SendString(sock,"Host:www.baidu.com\r\n");
SendString(sock,"Accept: */*\r\n");
SendString(sock,"User-Agent: Mozilla/4.0");
SendString(sock,"(compatible; MSIE 7.00; Windows 98)\r\n");
SendString(sock,"Connection:close\r\n");
SendString(sock,"\r\n");
SendString(sock,"\r\n");//最后要加空行

SendString函数是用来向指定套接字发送指定字符串。

这样一来就可以顺利实现网络爬虫的网页抓取功能了,如果想要继续扩展,可以查阅网络爬虫的相关资料,在这基础上实现和扩展自己的网络爬虫工具~~


0 0
原创粉丝点击