本文转自 http://blog.csdn.net/bodybo/article/details/7274865
写代码经常会遇到socket要通过代理连接服务器的情况,代理类型通畅有三种:HTTP、SOCK4和SOCK5,通过学习和网上参考相关代码,写了个代理类来实现该功能,贴出来与大家共享
才贴出来两天,刚在百度一搜竟然发现已被一字不改的转载到好几个网站去了,连转载的字样都没有,不反对转载分享,可能否注明出处?
头文件
#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; };
实现文件
#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类
头文件
#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); };
#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; }