偶身为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 );
- wVersionRequested:一个WORD(双字节)型数值,在最高版本的Windows Sockets支持调用者使用,高阶字节指定小版本(修订本)号,低位字节指定主版本号。现在的版本应该是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);
- af:一个地址描述。目前仅支持AF_INET格式,也就是说ARPA Internet地址格式。
- type:指定socket类型。新套接口的类型描述类型,如TCP(SOCK_STREAM)和UDP(SOCK_DGRAM)。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。
- protocol:顾名思义,就是指定协议。套接口所用的协议。如调用者不想指定,可用0。常用的协议有,IPPROTO_TCP、IPPROTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。
函数说明:bind()用来设置给参数sockfd 的socket 一个名称. 此名称由参数my_addr 指向一sockaddr 结构,对于不同的socket domain 定义了一个通用的数据结构
- sockfd:由socket()创建的要绑定地址的套接字ID
- my_addr:要绑定的地址(IP+Port)
- addrlen:要绑定地址的结构体大小
- sockfd:一个已绑定未被连接的套接字描述符
- backlog:连接请求队列(queue of pending connections)的最大长度(一般由2到4),如果用SOMAXCONN,则大小由系统确定。
- sockfd:之前设置的监听套接字,这个套接字用来监听一个端口,当有一个客户与服务器连接时,它使用一个端口号,而此时这个端口号正与这个套接字关联。当然客户不知道套接字这些细节,它只知道一个地址和一个端口号。
- addr:这是一个结果参数,它用来接受一个返回值,这返回值指定客户端的地址,当然这个地址是通过某个地址结构来描述的,用户应该知道这一个什么样的地址结构。如果对客户的地址不感兴趣,那么可以把这个值设置为NULL。
- len:它也是结果的参数,用来接受上述addr的结构的大小的,它指明addr结构所占有的字节个数。同样的,它也可以被设置为NULL。
- s:一个用于标识已连接套接口的描述字。
- buf:包含待发送数据的缓冲区。
- len:缓冲区中数据的长度。
- flags:调用执行方式。通常设置为0。
- s:一个标识套接口的描述字。
- buf:包含待发送数据的缓冲区。
- len:buf缓冲区中数据的长度。
- flags:调用方式标志位。
- to:(可选)指针,指向目的套接口的地址。
- tolen:to所指地址的长度。
- s:指定接收端套接字描述符;
- buf:指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;
- len:指明buf的长度;
- flags:调用方式标志位,一般置0。
- sockfd:标识一个已连接套接口的描述字。
- buf:接收数据缓冲区。
- len:缓冲区长度。
- flags:调用操作方式。
- from:(可选)指针,指向发送数据的套接口的地址。
- fromlen:from所指地址的长度。
- s:标识一个未连接套接口的描述字。
- name:欲进行连接的地址。
- namelen:名字长度。
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");//最后要加空行