本文转自 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. 训练指南 UVALive - 5135 (双连通分量)

    layout: post title: 训练指南 UVALive - 5135 (双连通分量) author: "luowentaoaa" catalog: true mathja ...

  2. Codeforces #442 Div2 F

    #442 Div2 F 题意 给出一些包含两种类型(a, b)问题的问题册,每本问题册有一些题目,每次查询某一区间,问有多少子区间中 a 问题的数量等于 b 问题的数量加 \(k\) . 分析 令包含 ...

  3. NOIP2018提高组模拟题(六)

    购物(shop) Description 小林来到商店中进行购物.商店里一共有 n 件物品,第 i 件物品的价格为 a[i] 元.小林总共需要购买 m 件物品,他希望他所花费的钱最少,请你计算出最小 ...

  4. 32、Django实战第32天:我的收藏

    我的收藏有3个页面:课程机构,授课教师,公开课程 课程机构 1.编辑usercenter-fav-org.html继承usercenter-base.html 2.编辑users.views.py . ...

  5. [BZOJ4817]树点涂色

    第一个操作比较麻烦,但可以看出它和lct里的access操作差不多,所以可以利用lct的性质巧妙维护操作1 直接用lct维护树中同颜色的链(因为染色操作是从$x$染到根所以同颜色的点一定形成一条链), ...

  6. 【点分治】bzoj1316 树上的询问

    #include<cstdio> #include<algorithm> #include<cstring> using namespace std; #defin ...

  7. Problem C: 零起点学算法18——3个数比较大小

    #include<stdio.h> int main() { int a,b,c; while(scanf("%d %d %d",&a,&b,& ...

  8. Scala高手实战****第19课:Scala的包、继承覆写及Spark源码鉴赏

    1.SparkSession.scala //导入某个类 import scala.beans.Introspector //导入某包下所有的类 import scala.beans._ //导入某包 ...

  9. TCP长连接与短连接的区别(转)

    1. TCP连接 当网络通信时采用TCP协议时,在真正的读写操作之前,server与client之间必须建立一个连接,当读写操作完成后,双方不再需要这个连接时它们可以释放这个连接,连接的建立是需要三次 ...

  10. 如何移除inline-block元素之间的空白

    我们想要的是<li>元素可以紧贴在一起,但是很显然,结果“出乎意料”.那么有什么方法可以让结果符合我们的预期呢?所能想到的解决方法至少有以下四种,而每种方法也都有其优劣所在,至于要如何选择 ...