本文转自 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 = ;
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 = ;
timeout.tv_usec =;
ret = select(, , &r, , &timeout); if (ret <= )
{
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 = ;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&nTimeout, sizeof(int)); //设置接收超时 unsigned long ul = ;
ret = ioctlsocket(socket, FIONBIO, (unsigned long*)&ul); //设置阻塞方式连接 switch(m_proxyType)
{
case : //HTTP
return ConnectByHttp(socket, ip, port);
break;
case : //SOCK4
return ConnectBySock4(socket, ip, port);
break;
case : //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[]; 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[]; memset(buf, , sizeof(buf));
struct TSock4req1 *proxyreq;
proxyreq = (struct TSock4req1*)buf;
proxyreq->VN = ;
proxyreq->CD = ;
proxyreq->Port = ntohs(port);
proxyreq->IPAddr = inet_addr(ip.c_str()); Send(socket, buf, ); struct TSock4ans1 *proxyans;
proxyans = (struct TSock4ans1*)buf;
memset(buf, , sizeof(buf)); Receive(socket, buf, sizeof(buf));
if(proxyans->VN == && proxyans->CD == )
{
return SUCCESS;
}
else
{
return CONNECT_SERVER_FAIL;
}
} ProxyStatus CProxy::ConnectBySock5(SOCKET socket, string ip, u_short port)
{
char buf[]; struct TSock5req1 *proxyreq1;
proxyreq1 = (struct TSock5req1 *)buf;
proxyreq1->Ver = ;
proxyreq1->nMethods = ;
proxyreq1->Methods = m_proxyUserName != "" ? : ; Send(socket, buf, ); struct TSock5ans1 *proxyans1;
proxyans1 = (struct TSock5ans1 *)buf; memset(buf, , sizeof(buf));
Receive(socket, buf, sizeof(buf));
if(proxyans1->Ver != || (proxyans1->Method != && proxyans1->Method != ))
{
return CONNECT_SERVER_FAIL;
} if(proxyans1->Method == )
{
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[] = ;
buf[] = nUserLen;
memcpy(buf + , m_proxyUserName.c_str(), nUserLen);
buf[ + nUserLen] = nPassLen;
memcpy(buf + + nUserLen, m_proxyUserPwd.c_str(), nPassLen); Send(socket, buf, + nUserLen + nPassLen); struct TAuthans *authans;
authans = (struct TAuthans *)buf;
memset(buf, , sizeof(buf)); Receive(socket, buf, sizeof(buf));
if(authans->Ver != || authans->Status != )
{
return CONNECT_SERVER_FAIL;
}
} memset(buf, , sizeof(buf));
struct TSock5req2 *proxyreq2;
proxyreq2 = (struct TSock5req2 *)buf;
proxyreq2->Ver = ;
proxyreq2->Cmd = ;
proxyreq2->Rsv = ;
proxyreq2->Atyp = ;
unsigned long tmpLong = inet_addr(ip.c_str());
unsigned short port1 = ntohs(port);
memcpy((char*)&proxyreq2->other, &tmpLong, );
memcpy((char*)(&proxyreq2->other) + , &port1, ); //Send(socket, buf, sizeof(struct TSock5req2) + 5);
Send(socket, buf, );
struct TSock5ans2 *proxyans2;
memset(buf ,, sizeof(buf));
proxyans2 = (struct TSock5ans2 *)buf; Receive(socket, buf, sizeof(buf));
if(proxyans2->Ver != || proxyans2->Rep != )
{
return CONNECT_SERVER_FAIL;
} return SUCCESS;
} int CProxy::Receive(SOCKET socket, char* buf, int bufLen)
{
return recv(socket, buf, bufLen, );
} bool CProxy::Send(SOCKET socket, const char* buf, int len)
{
long ilen = len;
int sendCnt = ;
int ret; while(sendCnt < ilen)
{
if((ret = send(socket, buf + sendCnt, ilen - sendCnt, )) == 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[]={};
int LineLength=;
for(int i=;i<(int)(DataByte / );i++)
{
Tmp[] = *Data++;
Tmp[] = *Data++;
Tmp[] = *Data++;
strEncode+= EncodeTable[Tmp[] >> ];
strEncode+= EncodeTable[((Tmp[] << ) | (Tmp[] >> )) & 0x3F];
strEncode+= EncodeTable[((Tmp[] << ) | (Tmp[] >> )) & 0x3F];
strEncode+= EncodeTable[Tmp[] & 0x3F];
if(LineLength+=,LineLength==) {strEncode+="\r\n";LineLength=;}
}
//对剩余数据进行编码
int Mod=DataByte % ;
if(Mod==)
{
Tmp[] = *Data++;
strEncode+= EncodeTable[(Tmp[] & 0xFC) >> ];
strEncode+= EncodeTable[((Tmp[] & 0x03) << )];
strEncode+= "==";
}
else if(Mod==)
{
Tmp[] = *Data++;
Tmp[] = *Data++;
strEncode+= EncodeTable[(Tmp[] & 0xFC) >> ];
strEncode+= EncodeTable[((Tmp[] & 0x03) << ) | ((Tmp[] & 0xF0) >> )];
strEncode+= EncodeTable[((Tmp[] & 0x0F) << )];
strEncode+= "=";
} return strEncode;
} string CBase64::Decode(const char* Data,int DataByte,int& OutByte)
{
//解码表
const char DecodeTable[] =
{
, , , , , , , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , , , ,
, // '+'
, , ,
, // '/'
, , , , , , , , , , // '0'-'9'
, , , , , , ,
, , , , , , , , , , , , ,
, , , , , , , , , , , , , // 'A'-'Z'
, , , , , ,
, , , , , , , , , , , , ,
, , , , , , , , , , , , , // 'a'-'z'
};
//返回值
string strDecode;
int nValue;
int i= ;
while (i < DataByte)
{
if (*Data != '\r' && *Data!='\n')
{
nValue = DecodeTable[*Data++] << ;
nValue += DecodeTable[*Data++] << ;
strDecode+=(nValue & 0x00FF0000) >> ;
OutByte++;
if (*Data != '=')
{
nValue += DecodeTable[*Data++] << ;
strDecode+=(nValue & 0x0000FF00) >> ;
OutByte++;
if (*Data != '=')
{
nValue += DecodeTable[*Data++];
strDecode+=nValue & 0x000000FF;
OutByte++;
}
}
i += ;
}
else// 回车换行,跳过
{
Data++;
i++;
}
}
return strDecode;
}

<转 >socket穿透代理代码(C++版)的更多相关文章

  1. Jenkins日常运维笔记-重启数据覆盖问题、迁移、基于java代码发版(maven构建)

    之前在公司机房部署了一套jenkins环境,现需要迁移至IDC机房服务器上,迁移过程中记录了一些细节:1)jenkins默认的主目录放在当前用户家目录路径下的.jenkins目录中.如jenkins使 ...

  2. 《OOC》笔记(4)——自动化地将C#代码转化为C代码(结构版)

    <OOC>笔记(4)——自动化地将C#代码转化为C代码(结构版) 我在<C表达面向对象语言的机制——C#版>中已经说明了从C#到C的转换方法.这次看<OOC>也是想 ...

  3. svn代码发版的脚本分享

    背景:开发将其代码放到svn里面,如何将修改后存放到svn里的代码发布到线上?简单做法:写个shell脚本,用于代码发版.比如开发的代码存放svn的路径是:svn://112.168.19.120/h ...

  4. cglib动态代理代码示例

    cglib动态代理代码示例 引用包cglib-xxx.jar 非Maven项目还需要手动引用包asm-xxx.jar 业务类(不需要定义接口) cglib代理类(实现接口MethodIntercept ...

  5. JDK动态代理代码示例

    JDK动态代理代码示例 业务接口 实现了业务接口的业务类 实现了InvocationHandler接口的handler代理类 1.业务接口 package com.wzq.demo01; /** * ...

  6. python2.7用socks和socket设置代理

    接下来是最近遇到的一个代理问题. 背景:一个基于python2.7的自动化测试项目 目的:因调试需求,需要通过代理连接其他公司的前端网站,来检验项目运行所在的问题. 问题:RUN>等了1分钟没有 ...

  7. 原生JS实现购物车结算功能代码+zepto版

    html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...

  8. Linux 网络编程详解二(socket创建流程、多进程版)

    netstat -na | grep " --查看TCP/IP协议连接状态 //socket编程提高版--服务器 #include <stdio.h> #include < ...

  9. 使用cow将socks5代理转为http代理(Windows版)

    自己租vps架设shadowsocks服务器,再配合chrome的SwitchyOmega插件科学上网一直很稳定,但是windows很多软件都不支持socks5,经常也会需要配置http代理做更新上传 ...

随机推荐

  1. 自己在用的几个sublime text3插件

    Arduino-like IDE ConvertToUTF8 Emmet(前身是zen coding) Keymap Redefiner Package Control PyV8 SideBarEnh ...

  2. (17)python 网络编程

    TCP连接的断点是由一个IP地址和一个端口号来唯一标识的 客户端/服务器 客户端总是最开始申请连接的一端,服务器则是等待客户端连接的一段 服务器的端口号如果不是特殊用土的一般应该大于1024,客户端则 ...

  3. Validate on POST data

    1. Basic validate  on bean's attribute. @Notnull @Max @Min @Pattern ... 2. Validate by logic 1) pass ...

  4. MySQL笔记之视图的使用详解

    原文:http://www.jb51.net/article/36363.htm 1.什么是视图 视图是从一个或多个表中导出来的表,是一种虚拟存在的表. 视图就像一个窗口,通过这个窗口可以看到系统专门 ...

  5. luogu P1064 金明的预算方案

    题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”.今 ...

  6. 【记忆化搜索】bzoj1055 [HAOI2008]玩具取名

    f(l,r,c)表示sl...sr能否被合成字符c. #include<cstdio> #include<cstring> using namespace std; int m ...

  7. 【二分】bzoj2083 [Poi2010]Intelligence test

    v[x]记录了x值的出现位置序列. 对每个b中的元素,每次在v[b[i]]中二分. 因此要记录上一次二分到了a数组的哪个位置. #include<cstdio> #include<v ...

  8. Problem D: 零起点学算法40——多组测试数据(求和)IV

    #include<stdio.h> int main() { int n,i,sum,a; ) { sum=; ;i<=n;i++) { scanf("%d",& ...

  9. 焦点改变事件OnFocusChangeListener

    效果图 1.MainActivity.java package com.example.app2; import android.support.v7.app.AppCompatActivity; i ...

  10. 使用Python的turtle模块画出最简单的五角星

    代码如下: import turtle def main(): t = turtle.Turtle() t.hideturtle() lengthOfSize = 200 drawFivePointS ...