写代码经常会遇到socket要通过代理连接服务器的情况,代理类型通畅有三种:HTTP、SOCK4和SOCK5,通过学习和网上参考相关代码,写了个代理类来实现该功能,贴出来与大家共享
头文件
[cpp] view plaincopy #pragma once
#include <WinSock2.h> #include <string> #include <vector>
using namespace std;
enum ProxyStatus { SUCCESS,CONNECT_PROXY_FAIL,NOT_CONNECT_PROXY,CONNECT_SERVER_FAIL };
class CProxy { public:CProxy(long type, string ip, u_short port, string username, string password)
:m_proxyType(type), m_proxyIp(ip), m_proxyPort(port), m_proxyUserName(username), m_proxyUserPwd(password)
{}
~CProxy(void){};
ProxyStatus ConnectProxyServer(SOCKET socket);ProxyStatus ConnectServer(SOCKET socket, string ip, u_short port);
private:ProxyStatus ConnectByHttp(SOCKET socket, string ip, u_short port);ProxyStatus ConnectBySock4(SOCKET socket, string ip, u_short port);ProxyStatus ConnectBySock5(SOCKET socket, string ip, u_short port);
bool Send(SOCKET socket, const char* buf, int len);int Receive(SOCKET socket, char* buf, int bufLen);
private:long m_proxyType;string m_proxyIp;u_short m_proxyPort;string m_proxyUserName;string m_proxyUserPwd;
bool m_blnProxyServerOk;};
struct TSock4req1 { char VN;char CD;unsigned short Port;unsigned long IPAddr;char other;};
struct TSock4ans1 { char VN;char CD;};
struct TSock5req1 { char Ver;char nMethods;char Methods;};
struct TSock5ans1 { char Ver;char Method;};
struct TSock5req2 { char Ver;char Cmd;char Rsv;char Atyp;char other;};
struct TSock5ans2 { char Ver;char Rep;char Rsv;char Atyp;char other;};
struct TAuthreq { char Ver;char Ulen;char Name;char PLen;char Pass;};
struct TAuthans { char Ver;char Status;};
实现文件[cpp] view plaincopy #include "StdAfx.h" #include "Proxy.h" #include "Base64.h" #include "log.h"
#include <time.h>
ProxyStatus CProxy::ConnectProxyServer(SOCKET socket)
{ int ret;struct timeval timeout ;fd_set r;string ip;u_short port;
ip = m_proxyIp;port = m_proxyPort;
sockaddr_in servAddr;servAddr.sin_family = AF_INET;servAddr.sin_addr.S_un.S_addr = inet_addr(ip.c_str());servAddr.sin_port = htons(port);
//设置非阻塞方式连接unsigned long ul = 1;ret = ioctlsocket(socket, FIONBIO, (unsigned long*)&ul);if(ret == SOCKET_ERROR)
{ return CONNECT_PROXY_FAIL;}
connect(socket, (sockaddr*)&servAddr, sizeof(sockaddr));
FD_ZERO(&r);FD_SET(socket, &r);timeout.tv_sec = 5;timeout.tv_usec =0;ret = select(0, 0, &r, 0, &timeout);
if (ret <= 0)
{ m_blnProxyServerOk = false;return CONNECT_PROXY_FAIL;} else { m_blnProxyServerOk = true;return SUCCESS;}
ProxyStatus CProxy::ConnectServer(SOCKET socket, string ip, u_short port)
{ int ret;int nTimeout;
if (!m_blnProxyServerOk)
{ return NOT_CONNECT_PROXY;}
nTimeout = 5000;setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&nTimeout, sizeof(int)); //设置接收超时
unsigned long ul = 0;ret = ioctlsocket(socket, FIONBIO, (unsigned long*)&ul); //设置阻塞方式连接
switch(m_proxyType)
{ case 0: //HTTP return ConnectByHttp(socket, ip, port);break;case 1: //SOCK4 return ConnectBySock4(socket, ip, port);break;case 2: //SOCK5 return ConnectBySock5(socket, ip, port);break;default:break;}
return CONNECT_SERVER_FAIL;}
ProxyStatus CProxy::ConnectByHttp(SOCKET socket, string ip, u_short port)
{ char buf[512];
if (m_proxyUserName != "")
{ string str;string strBase64;str = m_proxyUserName + ":" + m_proxyUserPwd;strBase64 = CBase64::Encode((unsigned char*)str.c_str(), str.length());sprintf_s(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\nAuthorization: Basic %s\r\n\r\nProxy-Authorization: Basic %s\r\n\r\n",ip.c_str(), port, ip.c_str(), port, strBase64.c_str(), strBase64.c_str());} else { //sprintf_s(buf, 512, "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n\r\n", ip.c_str(), port, ip.c_str(), port);sprintf_s(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.1\r\nUser-Agent: MyApp/0.1\r\n\r\n", ip.c_str(), port);}
Send(socket, buf, strlen(buf));Receive(socket, buf, sizeof(buf));
if (strstr(buf, "HTTP/1.0 200 Connection established") != NULL)
{ return SUCCESS;} else { return CONNECT_SERVER_FAIL;}
}
ProxyStatus CProxy::ConnectBySock4(SOCKET socket, string ip, u_short port)
{ char buf[512];
memset(buf, 0, sizeof(buf));struct TSock4req1 *proxyreq;proxyreq = (struct TSock4req1*)buf;proxyreq->VN = 4;proxyreq->CD = 1;proxyreq->Port = ntohs(port);proxyreq->IPAddr = inet_addr(ip.c_str());
Send(socket, buf, 9);
struct TSock4ans1 *proxyans;proxyans = (struct TSock4ans1*)buf;memset(buf, 0, sizeof(buf));
Receive(socket, buf, sizeof(buf));if(proxyans->VN == 0 && proxyans->CD == 90)
{ return SUCCESS;} else { return CONNECT_SERVER_FAIL;}
ProxyStatus CProxy::ConnectBySock5(SOCKET socket, string ip, u_short port)
{ char buf[512];
struct TSock5req1 *proxyreq1;proxyreq1 = (struct TSock5req1 *)buf;proxyreq1->Ver = 5;proxyreq1->nMethods = 1;proxyreq1->Methods = m_proxyUserName != "" ? 2 : 0;
Send(socket, buf, 3);
struct TSock5ans1 *proxyans1;proxyans1 = (struct TSock5ans1 *)buf;
memset(buf, 0, sizeof(buf));Receive(socket, buf, sizeof(buf));if(proxyans1->Ver != 5 || (proxyans1->Method != 0 && proxyans1->Method != 2))
{ return CONNECT_SERVER_FAIL;}
if(proxyans1->Method == 2)
{ int nUserLen = m_proxyUserName.length();int nPassLen = m_proxyUserPwd.length();//struct TAuthreq *authreq;//authreq = (struct TAuthreq *)buf;//authreq->Ver = 1;//authreq->Ulen = nUserLen;//strcpy(authreq->Name, m_proxyUserName.c_str());//authreq->PLen = nPassLen;//strcpy(authreq->Pass, m_proxyUserPwd.c_str());
buf[0] = 1;buf[1] = nUserLen;memcpy(buf + 2, m_proxyUserName.c_str(), nUserLen);buf[2 + nUserLen] = nPassLen;memcpy(buf + 3 + nUserLen, m_proxyUserPwd.c_str(), nPassLen);
Send(socket, buf, 3 + nUserLen + nPassLen);
struct TAuthans *authans;authans = (struct TAuthans *)buf;memset(buf, 0, sizeof(buf));
Receive(socket, buf, sizeof(buf));if(authans->Ver != 1 || authans->Status != 0)
{ return CONNECT_SERVER_FAIL;}
memset(buf, 0, sizeof(buf));struct TSock5req2 *proxyreq2;proxyreq2 = (struct TSock5req2 *)buf;proxyreq2->Ver = 5;proxyreq2->Cmd = 1;proxyreq2->Rsv = 0;proxyreq2->Atyp = 1;unsigned long tmpLong = inet_addr(ip.c_str());unsigned short port1 = ntohs(port);memcpy((char*)&proxyreq2->other, &tmpLong, 4);memcpy((char*)(&proxyreq2->other) + 4, &port1, 2);
//Send(socket, buf, sizeof(struct TSock5req2) + 5);Send(socket, buf, 10);struct TSock5ans2 *proxyans2;memset(buf ,0, sizeof(buf));proxyans2 = (struct TSock5ans2 *)buf;
Receive(socket, buf, sizeof(buf));if(proxyans2->Ver != 5 || proxyans2->Rep != 0)
{ return CONNECT_SERVER_FAIL;}
return SUCCESS;}
int CProxy::Receive(SOCKET socket, char* buf, int bufLen)
{ return recv(socket, buf, bufLen, 0);}
bool CProxy::Send(SOCKET socket, const char* buf, int len)
{ long ilen = len;int sendCnt = 0;int ret;
while(sendCnt < ilen)
{ if((ret = send(socket, buf + sendCnt, ilen - sendCnt, 0)) == SOCKET_ERROR)
{ return false;} else { sendCnt += ret;}
return true;}
proxy中用到的CBase64类
头文件
[cpp] view plaincopy #pragma once
#include <string>
using namespace std;
class CBase64 { private:CBase64(void);public:~CBase64(void);
static string Encode(const unsigned char* Data,int DataByte);static string Decode(const char* Data,int DataByte,int& OutByte);};
实现文件
[cpp] view plaincopy #include "StdAfx.h" #include "Base64.h"
CBase64::CBase64(void)
{ }
CBase64::~CBase64(void)
{ }
string CBase64::Encode(const unsigned char* Data,int DataByte)
{ //编码表const char EncodeTable[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";//返回值string strEncode;unsigned char Tmp[4]={0};int LineLength=0;for(int i=0;i<(int)(DataByte / 3);i++)
{ Tmp[1] = *Data++;Tmp[2] = *Data++;Tmp[3] = *Data++;strEncode+= EncodeTable[Tmp[1] >> 2];strEncode+= EncodeTable[((Tmp[1] << 4) | (Tmp[2] >> 4)) & 0x3F];strEncode+= EncodeTable[((Tmp[2] << 2) | (Tmp[3] >> 6)) & 0x3F];strEncode+= EncodeTable[Tmp[3] & 0x3F];if(LineLength+=4,LineLength==76) {strEncode+="\r\n";LineLength=0;} } //对剩余数据进行编码int Mod=DataByte % 3;if(Mod==1)
{ Tmp[1] = *Data++;strEncode+= EncodeTable[(Tmp[1] & 0xFC) >> 2];strEncode+= EncodeTable[((Tmp[1] & 0x03) << 4)];strEncode+= "==";} else if(Mod==2)
{ Tmp[1] = *Data++;Tmp[2] = *Data++;strEncode+= EncodeTable[(Tmp[1] & 0xFC) >> 2];strEncode+= EncodeTable[((Tmp[1] & 0x03) << 4) | ((Tmp[2] & 0xF0) >> 4)];strEncode+= EncodeTable[((Tmp[2] & 0x0F) << 2)];strEncode+= "=";}
return strEncode;}
string CBase64::Decode(const char* Data,int DataByte,int& OutByte)
{ //解码表const char DecodeTable[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,62, // '+' 0, 0, 0,63, // '/' 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9' 0, 0, 0, 0, 0, 0, 0,0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 'A'-'Z' 0, 0, 0, 0, 0, 0,26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 'a'-'z' };//返回值string strDecode;int nValue;int i= 0;while (i < DataByte)
{ if (*Data != '\r' && *Data!='\n')
{ nValue = DecodeTable[*Data++] << 18;nValue += DecodeTable[*Data++] << 12;strDecode+=(nValue & 0x00FF0000) >> 16;OutByte++;if (*Data != '=')
{ nValue += DecodeTable[*Data++] << 6;strDecode+=(nValue & 0x0000FF00) >> 8;OutByte++;if (*Data != '=')
{ nValue += DecodeTable[*Data++];strDecode+=nValue & 0x000000FF;OutByte++;} i += 4;} else// 回车换行,跳过{ Data++;i++;} return strDecode;}
|