Android Socks5代理服务器程序开发

Android Socks5代理服务器程序开发原理为处理移动端网络断连问题 实现应用无关 我们考虑采用 client proxy Internet 的三层架构 从 client proxy 这一环节 ProxyDroid 已经能够实现 因此接下来主要需要完成的工作是 proxy 的开发 proxy 与 Internet 互相之间的信息转发 以及剩余的从 proxy client 端信息传输 在 ProxyDroid 端我们采用了 Socks5 协议 它的优势是

原理

为处理移动端网络断连问题,实现应用无关。我们考虑采用client<->proxy<->Internet的三层架构。从client->proxy这一环节,ProxyDroid已经能够实现。

因此接下来主要需要完成的工作是

  1. proxy的开发
  2. proxyInternet互相之间的信息转发,以及剩余的从proxy->client端信息传输。

在ProxyDroid端我们采用了Socks5协议。它的优势是:无需proxy从报文内容中解析目的IP以及端口号,而是可以从正式数据传输前的握手信息获取。

Socks5代理工作模式

  1. client连接Socks5 proxy服务器端口
  2. client端发送命令{5,1,0}
  3. proxy返回应答{5,0},表示可以进行代理
  4. client发送:{5,1,0,1}+目的地址(4字节的16进制表示)+目的端口(2字节的16进制表示)
  5. proxy提取出IP地址、端口号与外网建立socket
  6. proxyclient返回应答:{5,0,0,1}+外网套接字绑定的IP地址(4字节的16进制表示)+外网套接字绑定的端口号(2字节的16进制表示)
  7. proxy不断检测client套接字,读出数据发送给外网
  8. proxy不断检测外网套接字,读出数据发送给client

代码

基本思想如下:

  1. 主活动类中会设置一个ServerSocket用于接收proxydroid发送过来的socks5报文从而建立socket,然后将该socket传递给服务器线程;
  2. 服务器线程与client端通信,建立从client与外网之间的交互链路。其中服务器线程自己作为中间媒介。

架构图

主活动

public class MainActivity extends AppCompatActivity { private String TAG = "SocketServer"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new Thread(new Runnable() { @Override public void run() { try { ServerSocket serverSocket = new ServerSocket(34500); //这里随机选择了一个端口,需与proxydroid中设置的端口一致 Log.d(TAG, "Port=" + serverSocket.getLocalPort()); while (true) { Socket socket = serverSocket.accept();//若获取不到会一直阻塞 new Thread(new ServerThread(socket)).start();//触发服务器线程 } }catch (Exception e){ e.printStackTrace(); } } }).start(); } } 

服务器线程

public class ServerThread implements Runnable { private Socket socket; private String TAG = this.getClass().getName(); private int BUFF_SIZE = 1024 * 100; public ServerThread(Socket socket) { this.socket = socket; } @Override public void run() { try { InputStream innerInputStream = socket.getInputStream(); OutputStream innerOutputStream = socket.getOutputStream(); byte[] buff = new byte[BUFF_SIZE]; int rc; ByteArrayOutputStream byteArrayOutputStream; / * client会向proxy发送510,所以这里执行的结果是buff={5,1,0} * Caution: 这里不能跟下面的innerInputStream.read(buff, 0, 10);合并成innerInputStream.read(buff, 0, 13); * 我试过,大部分情况没影响,但是偶尔会出现重大bug(读不出外网ip),至于原因暂不详 * 看来这种input和output类型的操作还是稳重一点,不要太心急 */ innerInputStream.read(buff, 0, 3); / * proxy向client发送应答{5,0} */ byte[] firstAckMessage = new byte[]{5, 0}; byte[] secondAckMessage = new byte[10]; innerOutputStream.write(firstAckMessage); innerOutputStream.flush(); / * client发送命令5101+目的地址(4Bytes)+目的端口(2Bytes) * 即{5,1,0,1,IPx1,IPx2,IPx3,IPx4,PORTx1,PORTx2} 一共10位 * 例如发送给52.88.216.252服务器的80端口,那么这里buff就是{5,1,0,1,52,88,-40,-4,0,80}(这里每位都是byte,所以在-128~127之间,可以自己换算成0~255) */ innerInputStream.read(buff, 0, 10); String IP = byte2int(buff[4]) + "." + byte2int(buff[5]) + "." + byte2int(buff[6]) + "." + byte2int(buff[7]); int port = byte2int(buff[8]) * 256 + byte2int(buff[9]); Log.e("ServerThread", "Connected to " + IP + ":" + port); Socket outerSocket = new Socket(IP, port); InputStream outerInputStream = outerSocket.getInputStream(); OutputStream outerOutputStream = outerSocket.getOutputStream(); / * proxy 向 client 返回应答5+0+0+1+因特网套接字绑定的IP地址(4字节的16进制表示)+因特网套接字绑定的端口号(2字节的16进制表示) */ byte ip1[] = new byte[4]; int port1 = 0; ip1 = outerSocket.getLocalAddress().getAddress(); port1 = outerSocket.getLocalPort(); secondAckMessage[0] = 5; secondAckMessage[1] = 0; secondAckMessage[2] = 0; secondAckMessage[3] = 1; secondAckMessage[4] = ip1[0]; secondAckMessage[5] = ip1[1]; secondAckMessage[6] = ip1[2]; secondAckMessage[7] = ip1[3]; secondAckMessage[8] = (byte) (port1 >> 8); secondAckMessage[9] = (byte) (port1 & 0xff); innerOutputStream.write(secondAckMessage, 0, 10); innerOutputStream.flush(); / * 应答线程:从外网不断读数据发到client */ SocksResponseThread responseThread = new SocksResponseThread(outerInputStream, innerOutputStream); responseThread.start(); / * 本线程:从client不断读数据发到外网 */ byteArrayOutputStream = new ByteArrayOutputStream(); while ((rc = innerInputStream.read(buff, 0, BUFF_SIZE)) > 0) { outerOutputStream.write(buff, 0, rc); byteArrayOutputStream.write(buff, 0, rc); outerOutputStream.flush(); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (socket != null) socket.close(); } catch (IOException e) { e.printStackTrace(); } } } public int byte2int(byte b) { return b & 0xff; } } 

应答线程

public class SocksResponseThread extends Thread { private InputStream in; private OutputStream out; private int BUFF_SIZE = 1024 * 100; public SocksResponseThread(InputStream in, OutputStream out) { this.in = in; this.out = out; } @Override public void run() { int readbytes = 0; byte buf[] = new byte[BUFF_SIZE]; while (true) { try { if (readbytes == -1) break; readbytes = in.read(buf, 0, BUFF_SIZE); if (readbytes > 0) { out.write(buf, 0, readbytes); } out.flush(); } catch (Exception e) { break; } } } } 
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/208406.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 上午11:40
下一篇 2026年3月19日 上午11:40


相关推荐

  • kafka删除topic数据_kafka查看topic列表

    kafka删除topic数据_kafka查看topic列表 kafka删除topic提示markedfordeletion [html] viewplain copy [root@logSer config]# kafka-topics.sh –delete –zookeeper localhost:2181 –topic test-group        Topic test-group…

    2022年10月9日
    4
  • 这7个web前端开发写代码软件,你过用几个?[通俗易懂]

    群里的朋友,经常问到web前端开发写代码用那个软件好?今天在这里统一回答下,主流的web前端开发写代码的软件有这些Webstorm、Vscode、SublimeText、HBuilder、Dreamweaver、notepad++、editplus等,做前端这么多年了,下面谈下我的使用感受吧。1.WebStorm【推荐】WebStorm是jetbra…

    2022年4月11日
    80
  • win10开虚拟机就重启_虚拟机装win10怎么用

    win10开虚拟机就重启_虚拟机装win10怎么用win10虚拟机自动关机可能是因为系统未激活导致!右键查看属性,可看到虚拟机的激活状态!如果显示未激活,需要激活!命令激活步骤:1.以管理员身份运行windowspowershell2.键入命令slmgr/ipkP9C2R-NM3BW-JR7DG-2R38J-D9MPF弹出窗口提示:“成功的安装了产品密钥”。红色部分为激活码,不可用的话,试试其他的(W269N-WFGW…

    2025年11月14日
    6
  • 史上最牛逼的CDH安装部署来了 亲测有效

    cdh安装部署错误史上最低可以试试

    2022年4月3日
    40
  • 莫比乌斯反演入门讲解

    莫比乌斯反演入门讲解莫比乌斯反演实际上是一两个公式定理的运用 自认为想要掌握它的话 其中的证明还是有必要了解的 看过网上一些博客 感觉都只证明了一半 没看到有人将这个定理完全证明出来 然而我最近在正好在学习初等数论 发现完全证明这个定理实际上并不需要很多知识 特此填坑 另外加上一些应用以构成完整的讲解 实际上 这个定理的证明用到了一点数论函数相关知识 前置技能在此 https blog csdn net t

    2026年3月18日
    2
  • C++函数模板(模板函数)详解

    C++函数模板(模板函数)详解定义用法:函数模板的原理延申用法2.1为什么需要类模板2.2单个类模板语法2.3继承中的类模板语法案例1:案例2:2.4类模板的基础语法2.5类模板语法知识体系梳理1.所有的类模板函数写在类的内部复数类:2.所有的类模板函数写在类的外部,在一个cpp中2.5总结关于类模板的几点说明:2.6类模板中的static关键字案例2:以下来自:C++类模板遇上static关键字…

    2022年4月4日
    52

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号