
#pragma comment(lib,"wsock32.lib")
#pragma comment(lib,"ws2_32.lib")
#include <process.h>
#include <winsock2.h>
#include <afx.h>
#include <afxwin.h>
#include "stdafx.h"
#define FD_NOEVENT 0
#define BACKUP 100
#define MAXDATALEN 65535
int ListenPort;
SOCKET ListenSock;
bool WsaStartupInfo;
typedef struct _CLIENTINFO
{
SOCKET clientsock;
sockaddr_in clientsockaddr;
} CLIENTINFO, *PCLIENTINFO;
CLIENTINFO HttpClientInfo;
//
typedef struct _SOCKINFO
{
SOCKET client_sock;
SOCKET server_sock;
} SOCKINFO, *PSOCKINFO;
SOCKINFO HttpSockInfo;
extern long SocketEventId(SOCKET remotesock);
extern unsigned long GetLocalIp();
extern unsigned long GetDomainIp(char domainname[250]);
extern void WsaStart();
extern int StartServer(int listenport);
extern UINT StartHttpProxy(int info);
extern UINT ServerThread(LPVOID info);
extern UINT SendThread(LPVOID info);
extern UINT ReciveThread(LPVOID info);
extern UINT SendThread(LPVOID info);
void exit();
void WsaStart()
{
WSADATA WsaData;
WORD wsaVer; //WORD A 16-bit unsigned integer.
wsaVer = MAKEWORD(2, 0); //The MAKEWORD macro creates an unsigned 16-bit integer by concatenating two given unsigned character values.
WsaStartupInfo = false;
if (WSAStartup(wsaVer, &WsaData) == 0)
{
WsaStartupInfo = true;
// printf("WSAStartup
");
}
}
int StartServer(int listenport)//开始代理服务
{
//printf("监听端口%d",ListenPort);
StartHttpProxy(listenport);
// _beginthread((void (*) (void *)) StartHttpProxy, 0, (LPVOID)NULL);
// AfxBeginThread(StartHttpProxy, (LPVOID)NULL); //创建线程,执行StartHttpProxy函数。
return 1;
}
UINT StartHttpProxy(int info) //一个线程,监听代理服务的端口
{
printf("代理服务器启动....
");
//端口监听线程
ListenPort=info;
SOCKET NewSock; //定义一个套接字
int socklen; //定义一个整形变量用来存放长度
sockaddr_in serversock, remotesock_addr; //定义两个地址
serversock.sin_family = AF_INET; //sin_family指代协议族,在socket编程中只能是AF_INET
serversock.sin_addr.S_un.S_addr = INADDR_ANY;//INADDR_ANY表示任何可绑定的地址
serversock.sin_port = htons(ListenPort);//将HttpListenPort中的端口号赋值给sin_port
// Sleep(300);
ListenSock = socket(AF_INET, SOCK_STREAM, 0);//全局变量HttpListenSock
// printf("创建套接字...
");
if (ListenSock == INVALID_SOCKET) //INVALID_SOCKET
{
printf("创建套接字失败,返回值值是:%d
",ListenSock);
return 0;
}
// Sleep(300);
// printf("创建套接字成功
");
if (bind(ListenSock, (const sockaddr*) &serversock, sizeof(serversock))== SOCKET_ERROR)//绑定套接字
{
printf("bind error.");
return 0;
}
// printf("bind.
");
// Sleep(300);
listen(ListenSock, BACKUP);//监听套接字HttpListenSock
// printf("listen.
");
socklen = sizeof(remotesock_addr);
// Sleep(100);
while (true)
{
printf("等待客户机连接....
");
NewSock = accept(ListenSock, (sockaddr*) &remotesock_addr, &socklen);//被动套接字
if (NewSock == INVALID_SOCKET)//判断被动套接字是否有效
{
Sleep(10);
continue;
}
// printf("被动套接字创建成功
");
ZeroMemory((void*) &HttpClientInfo, sizeof(CLIENTINFO));//HttpClientInfo是一个全局结构体变量,类型是CLIENTINFO
HttpClientInfo.clientsock = NewSock;
HttpClientInfo.clientsockaddr = remotesock_addr;
AfxBeginThread(ServerThread, (LPVOID) &HttpClientInfo);//创建一个线程运行HttpProxyServerThread函数,HttpClientInfo是形参。
Sleep(100);//延时
}
return 1;
}
UINT ServerThread(LPVOID info)
{
// printf("开始代理服务
");
//针对一次服务的线程
PCLIENTINFO pclientinfo;//定义一个结构体变量指针,指向CLIENTINFO类型。
SOCKET connectsock, clientsock;//定义两个套接字
sockaddr_in remotesock_addr;
char data[MAXDATALEN], url[250], temp[250], httpurl[250], portnum[10];
int datalen,index_start, index_end, port;
CString HttpString, UrlString, PortString;//CString 是VC定义的一个类。这里新建三个CString类的对象。
pclientinfo = (PCLIENTINFO)info;//将形参的地址赋给指针pclientinfo
clientsock = pclientinfo->clientsock;
ZeroMemory((void*)data, sizeof(data));//将data初始化为全是0
printf("连接到客户机,接受来自客户机的报文....
");
datalen = recv(clientsock, data, sizeof(data), 0);//接受来自client的信息,保存在data中
if (datalen <= 0)
{
printf("接受失败
");
closesocket(clientsock);
return 0;
}
//以下一段处理HTTP报文url段的代码
//将data中的字符串记录在HttpString对象中
//然后在HttpString中记录的字符串中找url标记的头和尾,位置分别用index_start和index_end标记
//然后将HttpString中的url读取到UrlString对象中。
printf("处理报文信息...
");
// printf("提取url
");
HttpString.Format("%s", data);
UrlString = HttpString;
index_start = HttpString.Find("Host: ", 0); //寻找url标记
if (index_start <= 0)
{
closesocket(clientsock);
return 0;
}
index_end = HttpString.Find("
", index_start);
if (index_end <= 0)
{
closesocket(clientsock);
return 0;
}
UrlString = HttpString.Mid(index_start + 6, index_end - index_start - 6);
//读取 url字符串
wsprintf(url, "%s", UrlString);
strcpy(temp, url);
strcat(temp, ":");
datalen = strlen(temp);
if (HttpString.Find("GET", 0) == 0)//如果在报文里找到了GET。则这是一个GET请求的报文
{
// printf("这是一个GET
");
//判断get命令,并处理
index_start = HttpString.Find(temp, 0);//在报文里面从头找url,位置标记到index_start
strcpy(httpurl, "http://");//先将http://拷贝到字串httpurl中
if (index_start > 0)//如果找到起始位
{
index_end = HttpString.Find("/", index_start);//在报文里从index_start的位置开始找“/”,位置标记在index_end
if (index_end <= 0)
{
closesocket(clientsock);
return 0;
}
PortString = HttpString.Mid(index_start + datalen, index_end - index_start - datalen);//把HttpString中找到的端口号放到PortString里
port = atoi(PortString);//将端口号经过类型转换赋值到port
strcat(httpurl, temp);//将temp,也就是url+":"拷贝到httpurl中http://字段的后面。
itoa(port, portnum, sizeof(portnum));
strcat(httpurl, portnum);//将端口号拷贝到httpurl的http://+url+":"后面
strcat(httpurl, "/");//在httpurl的http://+url+":"+端口号后面加上/
}
else//否则,没有找到,说明使用了默认的80端口
{
port = 80;
strcat(httpurl, url);
strcat(httpurl, "/");
}
HttpString.Replace(httpurl, "/");//将报文中的httpurl替换成/
HttpString.Replace("Proxy-", "");//将Proxy-去掉
HttpString.Replace("HTTP/1.0", "HTTP/1.1");//将报文支持的HTTP版本号换成1.1
}
else if (HttpString.Find("CONNECT", 0) == 0)
{
//判断connect命令并处理
// printf("这是一个CONNECT
");
index_start = HttpString.Find(temp, 0);//从头开始在报文里找url:,位置标记在index_start
if (index_start > 0)
{
index_end = HttpString.Find(" ", index_start);//从index_start后开始找第一个空格,位置标记在index_end
if (index_end <= 0)
{
closesocket(clientsock);
return 0;
}
PortString = HttpString.Mid(index_start + datalen, index_end - index_start - datalen);//拷贝端口号
port = atoi(PortString);//端口号类型转换
}
else
{
closesocket(clientsock);
return 0;
}
}
//将上面提出的信息用开设定与远程主机的连接
// printf("设置远程主机地址与端口
");
remotesock_addr.sin_family = AF_INET;
remotesock_addr.sin_port = htons(port);
remotesock_addr.sin_addr.S_un.S_addr = GetDomainIp(url);
connectsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
printf("正在连接服务器....
");
if (connect(connectsock, (const sockaddr*) &remotesock_addr, sizeof(remotesock_addr)) == INVALID_SOCKET)
{
//连接远程主机
printf("连接服务器失败
");
closesocket(clientsock);
return 0;
}
ZeroMemory((void*)data, sizeof(data));//清空data
wsprintf(data, "%s", HttpString);//将HttpString以字符串输出到data中
datalen = strlen(data);//量一下data的大小
printf("连接服务器成功,向服务器发送HTTP报文
");
if (HttpString.Find("CONNECT", 0) < 0)//如果HTTP不是CONNECT