原文转自:http://www.cppblog.com/zuhd/archive/2010/06/08/117366.html

sock代理分为sock4代理和 sock5代理。sock4支持TCP(事实仅支持TCP),无需用户名、密码验证;sock5支持TCP和UDP,根据代理服务器设置是否需要用户名、密码认证。TCP和UDP代理工作原理产不多,UDP代理网上多的是,google一下即可。这里只讲TCP代

理工作原理。
sock代理工作原理大致如下:
1。[需要代理方]向服务器发出请求信息;
2。[代理方]应答;
3。[需要代理方]接到应答后发送向[代理方]发送目的ip和端口;
4。[代理方]与目的连接;
5。[代理方]将[需要代理方]发出的信息传到目的方,将目的方发出的信息传到[需要代理方];
6。代理完成。
下面对sock4和sock5的代理工作原理流程分别详细说明,并给出示例代码。
sock4的TCP代理工作流程:
1。我们首先还是连接服务器,然后发送数据给服务器。由于是无用户密码验证,我们需要发送9个字节的数据,展开写为 04 01 + 目标端口(2字节) + 目标IP(4字节) + 00,其中目标端口和目标IP就是我们真正要连接的服务器端口和服务器地址;
2。代理服务器返回8字节的数据,我们只要判断第二字节是否为90即可,若是90连接成功,否则失败.剩下的操作和不存在代理服务器一样,可直接用发送\接受数据。
sock5的TCP代理工作流程:
1。向服务器的代理端口建立tcp连接。一般为1080;
2。向服务器发送 05 02 00 02(此为16进制码,以下同),让代理服务器选择认证方式 ;
05
02 这里确认2种认证方式 无需认证和需要认证,只需要验证一种方式,可以直接发送05 01 00查询服务器是否支持无认证代理方式;
00 不需要认证;
02 需要认证;
3。如果接到 05 00 则是可以代理或则05 02需要认证,这里只需要判断第二字节就行;
如果需要认证,需要向服务器发送01 用户名长度(2字节)用户名 密码长度(2字节)密码,然后接收服务器返回数据,如果第二字节为 00,则认证通过,否则无法认证,则连接失败;
4。发送 05 01 00 01 + 目的地址(4字节)+ 目的端口(2字节),目的地址和端口都是16进制码(不是字符串)。
例202.103.190.27 - 7201
则发送的信息为:05 01 00 01 CA 67 BE 1B 1C 21
(CA=202 67=103 BE=190 1B=27 1C21=7201)
5。接收代理服务器返回的数据,我们只要判断第二字节是否为00即表示代理连接完成;
6。以后操作和直接与目的方进行TCP连接相同。

//代理服务器登录
CString g_proxyserver = "";
int  g_proxyport = 1080;
CString g_proxyuser = "";
CString g_proxypwd = "";
int  g_proxyid = 3;  //2 - sock4代理 3 - sock5代理
char server_name[100]= {0};  //真正的服务器地址
int  server_port=8000;   //真正的服务器端口
SOCKET ConnecToProxyServer()
{
 SOCKADDR_IN ToAddr;
 SOCKET m_hSocketpop = socket(AF_INET, SOCK_STREAM ,0);  // SOCK_DGRAM;
 memset(&ToAddr, 0, sizeof(ToAddr));
 ToAddr.sin_family = AF_INET;
 ToAddr.sin_addr.s_addr = inet_addr(g_proxyserver);//这是我的SOCKS服务器
 ToAddr.sin_port = htons(g_proxyport); 
 int retErr = connect(m_hSocketpop,(SOCKADDR*)&ToAddr,sizeof(ToAddr));
 if(retErr == SOCKET_ERROR)
 {
  closesocket(m_hSocketpop);
  return -1;
 }
 char buf[100] = {0};
 if(g_proxyid == 3) //sock5 代理方式
 {
  // 让PROXY选择认证方法
  buf[0] = 0x05;
  buf[1] = 0x02; //确认2种认证方式 无需认证和需要认证
  buf[2] = 0x00; // 无需认证
  buf[3] = 0x02; // 需要认证
  if(send(m_hSocketpop,(const far char*)buf,4,0) == SOCKET_ERROR)
  {
   closesocket(m_hSocketpop);
   return -1;
  }
  Sleep(100);
  if(recv(m_hSocketpop,buf,10,0) == SOCKET_ERROR)
  {
   closesocket(m_hSocketpop);
   return -1;
  }
  if(buf[1] == 0x02)
  {//需要认证
   char userStr[128] = {0};
   userStr[0]=0x01;
   userStr[1]=g_proxyuser.GetLength();
   strcpy(userStr+2,g_proxyuser);
   userStr[2+g_proxyuser.GetLength()]=g_proxypwd.GetLength();
   strcpy(userStr+3+g_proxyuser.GetLength(),g_proxypwd);
   int result=send(m_hSocketpop,userStr,strlen(userStr), 0);
   if(result == SOCKET_ERROR)
   {
    closesocket(m_hSocketpop);
    return -1;
   }
   Sleep(100);
   char validateChar[2] = {1};
   result=recv(m_hSocketpop,validateChar,2, 0);
   if(result == SOCKET_ERROR)
   {
    closesocket(m_hSocketpop);
    return -1;
   }
   if(validateChar[1]!='\x00')
   {//认证失败
    closesocket(m_hSocketpop);
    return -1;
   }
  }
  // 向PROXY服务器发送CONNECT 请求,
  memset(buf, 0, 100);
  buf[0] = 0x05;
  buf[1] = 0x01; // connection request.
  buf[2] = 0x00; // reserved!
  buf[3] = 0x01; // address type:Ip V4 ;
  *((ULONG*)(buf+4))=inet_addr(server_name);
  *((USHORT*)(buf+8))=htons(server_port);
  if(send(m_hSocketpop,(const far char*)buf,10,0) == SOCKET_ERROR)
  {
   closesocket(m_hSocketpop);
   return -1;
  }
  Sleep(100);
  // 接收PROXY服务器返回的REPLY
  memset(buf, 1, 100);
  if(recv(m_hSocketpop,buf, 20,0) == SOCKET_ERROR)
  {
   closesocket(m_hSocketpop);
   return -1;
  }
  if(buf[1] != 0) // 只有当第二个字节为0时,才表示成功。
  {
//   printf("Cannot connect to the remote server!\n");
   closesocket(m_hSocketpop);
   return -1;
  }
//  theApp.m_ClientSocket.Attach(m_hSocketpop);
 }
 if(g_proxyid == 2) //sock4 代理方式
 {
  int result;
  memset(buf, 0, 100);
  buf[0] = 0x04;
  buf[1] = 0x01; // connection request.
  *((USHORT*)(buf+2))=htons(server_port);
  *((ULONG*)(buf+4))=inet_addr(server_name);
  buf[8] = 0x00;
  result = send(m_hSocketpop, (const far char*)buf, 9, 0);
  if(result == SOCKET_ERROR)
  {
   closesocket(m_hSocketpop);
   return -1;
  }
  Sleep(100);
  char EchoStr[10];
  memset(EchoStr,0,10);
  result=recv(m_hSocketpop,EchoStr,8, 0);
  if(result == SOCKET_ERROR)
  {
   closesocket(m_hSocketpop);
   return -1;
  }
  if(EchoStr[1] != 90)
  {
   closesocket(m_hSocketpop);
   return -1;
  }
//  theApp.m_ClientSocket.Attach(m_hSocketpop);
 }
 return m_hSocketpop;
}
调用方式:
  strcpy(server_name, theApp.m_ServerIP);
  server_port = 8080;
  SOCKET m_socket = ConnecToProxyServer();
  if(m_socket == -1)
  {
        return 0;
  }
  int type = 1000;
  send(m_socket, (char*)&type, sizeof(int), 0);

SOCK5如何用代理UDP连接

1。向服务器的1080端口建立tcp连接

2。向服务器发送 05 01 00

3。如果接到 05 00 则是可以代理

4。发送 05 03 00 01 00 00 00 00 + 本地UDP端口(2字节)

5。服务器返回 05 00 00 01 +服务器地址+端口

7.需要申请方发送
00 00 00 01 +目的地址IP(4字节)+目的端口 +所要发送的信息

8。当有数据报返回时
向需要代理方发出00 00 00 01 +来源地址IP(4字节)+来源端口 +接受的信息
 
使用sock5代理时TCP数据:
客户端   sock5服务器
SYN
   ACKSYN
ACK
05 01 00 00 00 00 
   05 00 00 00 00 00
05 01 00 03 0E 31 39 32 2E 31 36 38 2E 37 35 2E 31 31 34 00 6E (.....192.168.75.114.n)
   05 00 00 01 C0 A8 4D 56 08 D4
ACK
   +OK X1 NT-POP3 Server iflytek.com (IMail 8.15 228888-9)..
USER hjma..
   +OK send your password..
PASS xxxxxxx..
   +OK maildrop locked and ready..
STAT..
   +OK 0 0..
QUIT..
   +OK POP3 Server saying Good-Bye..
ACKFIN
   ACK
   ACKFIN
ACK

<转>sock代理服务原理(TCP穿透)的更多相关文章

  1. 用TCP穿透NAT(TCP打洞)的实现

    目录 TCP穿透原理 程序思路 声明 上代码 运行示例 1. TCP穿透原理: 我们假设在两个不同的局域网后面分别有2台客户机A和 B,AB所在的局域网都分别通过一个路由器接入互联网.互联网上有一台服 ...

  2. 转发 通过NAT和防火墙特性和TCP穿透的测评(翻译)

    转自 http://blog.csdn.net/sjin_1314/article/details/18178329 原文:Characterization and Measurement of TC ...

  3. DNS原理-HTTP原理-TCP原理

    第一章:企业DNS原理 相信大家都知道windows和linux的hosts文件是:IP地址和域名的对应关系,我们一般访问网站的步骤: 打开网页-----输入网址-------查看本地的DNS库是否存 ...

  4. SOCK开发之---TCP/IP简介

    在开发通信程序之前,都要先确定这些程序相互通信所使用的协议(protocol),在深入设计前,我们都需要先从高层次来判断通信由哪个程序发起以及相应在何时产生. 举例来说,一般认为web服务器是一个长时 ...

  5. 黏包的原理 (tcp udp) struct模块

    黏包 指数据混乱问题(发送端发送数据,接收端不知如何去接收) 只有tcp协议才会发送粘包,udp不会发生 黏包(tcp) 有一个合包机制(nagle算法),将多次连续发送且间隔较小的数据,进行打包成一 ...

  6. 计算机网络原理,TCP&UDP

    UDP伪首部:计算校验和时会用到,然后实际传输过程中里包含的IP地址没有什么用. UDP校验和计算:求数值之和,如果溢出回卷,最后求出反码;UDP伪首部,UDP首部,应用层数据相加 tcp报文,最短2 ...

  7. 移动端300ms延迟原理,穿透、遮罩层滑动导致下面滑动总结

    遮罩层滑动导致下面滑动 1,阻止弹层滑动,使用默认事件,使用这种方式弹层不能滑动 document.getElementById("model").addEventListener ...

  8. 关于使用UDP(TCP)跨局域网,NAT穿透的心得

    前言:        最近我用java做了一个C/S的类似QQ之类的IM系统(即时通讯系统),遇到了不能跨局域网通讯的问题,经过在网上,和书上查阅了一些资料,了解了一些情况,现在就总结一下我的解决方案 ...

  9. 使用TCP协议的NAT穿透技术

    一直以来,说起NAT穿透,很多人都会被告知使用UDP打孔这个技术,基本上没有人会告诉你如何使用TCP协议去穿透(甚至有的人会直接告诉你TCP协议是无法实现穿透的).但是,众所周知的是,UDP是一个无连 ...

随机推荐

  1. (转) C#解惑:HashSet<T>类

    HashSet<T>是一个相对“冷门”的类型,平时在项目中用得不多,但是在特定的业务中可以大用. 先来了解下HashSet<T>类,主要被设计用来存储集合,做高性能集运算,例如 ...

  2. ( 转 ) 优化 Group By -- MYSQL一次千万级连表查询优化

    概述: 交代一下背景,这算是一次项目经验吧,属于公司一个已上线平台的功能,这算是离职人员挖下的坑,随着数据越来越多,原本的SQL查询变得越来越慢,用户体验特别差,因此SQL优化任务交到了我手上. 这个 ...

  3. CentOS 7 下nagios搭建记录

    跟随 园子的文章搭建 http://www.cnblogs.com/mchina/archive/2013/02/20/2883404.html 1.遇 nagios插件地址迁移错误,记录解决. 2. ...

  4. wildfly 10的安装部署

    http://www.xue163.com/2203/1/22037981_2.html WildFly 曾用名:JBoss Application Server ,红帽公司宣布 JBoss AS 的 ...

  5. 【kruscal】【最小生成树】【块状树】bzoj3732 Network

    跟去年NOIP某题基本一样. 最小生成树之后,就变成了询问连接两点的路径上的权值最大的边. 倍增LCA.链剖什么的随便搞. 块状树其实也是很简单的,只不过每个点的点权要记录成“连接其与其父节点的边的权 ...

  6. 【贪心】bzoj3709 [PA2014]Bohater

    把怪分成两类看: 一.回血>损血 则若先杀损血少的再杀损血多的,则为当前这一步提供了更高的可能性.因为血量是单增的,所以尽量用较少的血量去干♂耗血较少的怪物. 二.回血<损血 则若先杀回血 ...

  7. 1.2(学习笔记)Servlet基础(doGet、doPost、生命周期、页面跳转)

    一.doGet()与doPost() 我们在TestServlet类中重写doGet().doPost().service(). import javax.servlet.ServletExcepti ...

  8. 7.2(java学习笔记)URL

    一.URL URL类表示统一资源定位符,指向万维网上“资源”的指针. 资源可以是简单的文件或目录,也可以是对更复杂对象的引用,比如对数据库或搜索引擎的查询. URL即是定位也是资源,定位到网络中一个具 ...

  9. Java高级架构师(一)第30节:把应用部署到Linux服务器上

  10. iOS开发——使用Autolayout生成动态高度的TableViewCell单元格

    步骤一.TableViewCell中使用Autolayout 要点:Cell的高度必须在Constraints中指明,但不能定死,需要让内部由内容决定高度的View决定动态高度. 如UILabel设置 ...