一、 前言
网上使用C/C++ socket发送http请求的资料有很多很多。
代理服务器的原理资料也不少。
但是如何使用C/C++通过代理进行http请求的资(源)料(码)却没有找到。
也不知道是不是我的关键字搜索的不对。。。
所以准备自己研究一把。
二、 第一步:分析
分析代理服务器原理:
客户端 <==> 代理服务器 <==> 目的服务器
看到这,灵感一闪,创建socket的时候应该使用“代理服务器”的地址和端口,而不是目的服务器的地址和端口,马上撸码测试。
三、 第二步:撸码测试
使用“代理服务器”的地址和端口创建socket,然后把http request发送到“代理服务器”。
编译运行。
失败了,看来没有这么简单,得抓个包看看浏览器是怎么办到的。
四、 第三步:抓包
我PC地址:192.168.32.165
代理服务器地址:192.168.38.7
目的地址:www.google.com
使用chrome(浏览器已经配置了http代理)访问www.google.com,然后抓包,看看浏览器是如何实现代理上网的。
发现了两条可疑数据,如下图:

"CONNECT www.google.com:443 HTTP/1.1" 443是默认的https端口
五、 第四步:再撸码测试
编码发送"CONNECT www.google.com:443 HTTP/1.1"到代理服务器测试,
编译运行,竟然成功了,不可思议。
下面贴上测试代码,如有遗漏或者错误请大家帮忙指出,感激不尽!
#include <stdio.h>
#include <Winsock2.h>
#pragma comment(lib, "Ws2_32.lib")
#define USE_PROXY 1
#define PROXY_ADDR "192.168.38.7"
#define PROXY_PORT 3128
#if USE_PROXY
SOCKET _connect(const char *addr, unsigned short port)
#else
SOCKET _connect(struct in_addr *addr, unsigned short port)
#endif
{
SOCKET sockfd = INVALID_SOCKET;
struct sockaddr_in sin = { 0 };
int ret = 0;
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == sockfd)
{
printf("socket failed.\n");
return sockfd;
}
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
#if USE_PROXY
sin.sin_addr.s_addr = inet_addr(addr);
#else
sin.sin_addr = *addr;
#endif
ret = connect(sockfd, (struct sockaddr*)&sin, sizeof(struct sockaddr_in));
if (0 != ret)
{
printf("socket failed.\n");
closesocket(sockfd);
sockfd = INVALID_SOCKET;
}
return sockfd;
}
void _close(SOCKET sockfd)
{
if (INVALID_SOCKET != sockfd)
{
closesocket(sockfd);
}
}
void connect_proxy(SOCKET sockfd)
{
// proxy user and password: dXNlcm5hbWU6cGFzc3dvcmQ= is "username:password" with base64 encode
const char *header = "CONNECT www.baidu.com:80 HTTP/1.1\r\nProxy-Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=\r\n\r\n";
int offset = 0;
char buf[1024] = { 0 }; // buf maybe not enough, to malloc it dynamically...
send(sockfd, header, strlen(header), 0);
// if success proxy server will response "HTTP/1.0 200 Connection established\r\n\r\n"
// TODO... check response
while (1)
{
recv(sockfd, buf+offset, 1, 0);
offset++;
if (offset >= 4)
{
if ('\n' == buf[offset - 1]
&& '\r' == buf[offset - 2]
&& '\n' == buf[offset - 3]
&& '\r' == buf[offset - 4])
{
break;
}
}
}
printf("%s", buf);
}
void http_request()
{
SOCKET sockfd = INVALID_SOCKET;
struct hostent *host = NULL;
char c;
const char *header = "GET / HTTP/1.1\r\nHost: www.baidu.com\r\n\r\n";;
#if USE_PROXY
sockfd = _connect(PROXY_ADDR, PROXY_PORT);
connect_proxy(sockfd);
#else
host = gethostbyname("www.baidu.com");
sockfd = _connect((struct in_addr*)host->h_addr_list[0], 80);
#endif
send(sockfd, header, strlen(header), 0);
// Just printf response
while (1)
{
recv(sockfd, &c, 1, 0);
printf("%c", c);
// if recv all
// break;
}
_close(sockfd);
}
int main()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
http_request();
WSACleanup();
return 0;
}
下面是运行结果

版权声明:本文为yu1121jm原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。