winsock编程使用HTTP代理(一)

代理服务我们比较熟悉了,常见的代理方式有HTTP,sock4,sock5。到底浏览器是怎么通过代理服务器访问目标资源的呢,我这里使用最简单的http代理服务来写个程序测试一下。

首先用socket编程模拟正常的HTTP请求,winsock的使用方法请参看我以前的一篇博文——链接。

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

void main()
{
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;

	wVersionRequested = MAKEWORD( 1, 1 );
	err = WSAStartup( wVersionRequested, &wsaData );
	if ( err != 0 ) {
		return;
	}
	if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) {
		WSACleanup();
		return; 
	}
	SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);

	/*
	* 初始化套接字
	*/
	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
	addrSrv.sin_family=AF_INET;
	addrSrv.sin_port=htons(80);
	
	connect(sockClient,(SOCKADDR *)&addrSrv,sizeof(SOCKADDR));

	/*
	* 通信
	*/
	char req[1000] = "GET / HTTP/1.1\r\n\
Host: 127.0.0.1\r\n\
User-Agent: Mozilla/5.0\r\n\
Accept: */*\r\n\
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n\
Connection: keep-alive\r\n\r\n";//Proxy-Connection: Keep-Alive\r\nConnection: Keep-Alive\r\n
	send(sockClient,req,strlen(req)+1,0);

	char recvBuffer[1000];
	memset(recvBuffer,NULL,sizeof(recvBuffer));
	recv(sockClient,recvBuffer,1000,0);
	printf("%s\n",recvBuffer);


	closesocket(sockClient);
	WSACleanup();
}
上面主要是模拟浏览器得HTTP请求头,发送GET命令以及请求头信息( 切记请求头部分不要缩进,请求头结尾处需要保留一个空行),然后运行控制台程序得到如下结果,一个简单的http请求就实现了。

HTTP/1.1 200 OK
Content-Type: text/html
Last-Modified: Fri, 29 Jun 2012 02:55:54 GMT
Accept-Ranges: bytes
ETag: "a7c2ab3a255cd1:0"
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Date: Fri, 29 Jun 2012 03:12:10 GMT
Content-Length: 5

Hello
请按任意键继续. . .
可以看到我们已经获取到网页资源了(响应状态码,响应头,响应正文),下面看看怎么通过HTTP代理来访问网页呢,其实原理都是一样的, 这时socket连接代理服务器而不是目标机器(我这里用的fookproxy,一个简单易用的代理服务器,监听8000端口),示例代码如下,我们可以看出仅仅是发送的内容做了变化。
#include<WinSock2.h>
#include<stdio.h>
#pragma comment(lib,"ws2_32.lib")

void main()
{
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;

	wVersionRequested = MAKEWORD( 1, 1 );
	err = WSAStartup( wVersionRequested, &wsaData );
	if ( err != 0 ) {
		return;
	}
	if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) {
		WSACleanup();
		return; 
	}
	SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);

	/*
	* 初始化套接字
	*/
	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
	addrSrv.sin_family=AF_INET;
	addrSrv.sin_port=htons(8000);
	
	connect(sockClient,(SOCKADDR *)&addrSrv,sizeof(SOCKADDR));

	/*
	* 通信
	*/

	char req[1000] = "GET http://www.baidu.com HTTP/1.1\r\n\
Host: www.baidu.com\r\n\
User-Agent: Mozilla/5.0\r\n\
Accept: */*\r\n\
Proxy-Connection: Keep-Alive\r\n\
Connection: keep-alive\r\n\r\n";
	send(sockClient,req,strlen(req)+1,0);

	char recvBuffer[1000];
	memset(recvBuffer,NULL,sizeof(recvBuffer));
	recv(sockClient,recvBuffer,1000,0);
	printf("%s\n",recvBuffer);

	closesocket(sockClient);
	WSACleanup();
}
通过代理服务器访问百度网页,得到的响应内容如下(其中正文部分因为是二进制方式,没法打印出来)
HTTP/1.0 200 OK
Content-Length: 8024
Proxy-Connection: keep-alive
Set-Cookie: BAIDUID=FF55356604AA5C6335A9B1BB09A66659:FG=1; expires=Fri, 29-Jun-4
2 03:27:32 GMT; path=/; domain=.baidu.com
Expires: Fri, 29 Jun 2012 03:27:32 GMT
Server: BWS/1.0
Cache-Control: private
Date: Fri, 29 Jun 2012 03:27:32 GMT
P3P: CP=" OTI DSP COR IVA OUR IND COM "
Content-Type: text/html;charset=gbk


请按任意键继续. . .

上面请求资源时必须写明GET http://www.baidu.com,而不能是GET www.baidu.com,不然代理服务器不知道目标资源是的什么协议,会返回如下错误信息

HTTP/1.0 502 ['Server: Unsupported Scheme', 'Server: Unsupported Scheme']

使用HTTP代理的方式非常简单,如果需要添加身份验证的话,需要在请求头中添加Proxy-Authorization: Basic dHQ6MTIz(其中最后那个字符串为用户名密码组合的base64编码),当然这之前代理服务器会返回客户端拒绝服务的提醒,并指定WWW-Authenticate响应头中包含身份验证方式(basic方式或者较为复杂安全的NTLM方式)。

你可能感兴趣的:(winsock编程使用HTTP代理(一))