原理

为处理移动端网络断连问题,实现应用无关。我们考虑采用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";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);new Thread(new Runnable() {@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}}}
}

Android Socks5代理服务器程序开发相关推荐

  1. android应用程序开发_Kotlin与Flutter:Android跨平台应用程序开发,到底选择哪个?...

    移动互联时代--应用为王 移动互联网时代,很难想象没有应用程序的生活.从我们睁眼醒来的那一刻到我们真正睡觉的那一刻,无数的应用程序围绕着我们.根据统计,国人平均在移动设备上花费4个小时以上! 而这其中 ...

  2. Android蓝牙串口程序开发

    本文主要介绍了针对android的蓝牙串口上位机开发. 程序下载地址:点击打开链接 一.帧定义 androidclient依照一定的数据帧格式通过蓝牙串口发送数据到连接到MCU的蓝牙从机.MCU接收到 ...

  3. Android vs iOS 程序开发:我该选哪一个?

    移动应用程序开发是软件生产中增长最稳定的领域之一.几年前来移动应用程序数量激增,对快速便捷应用程序的需求一直在增长.仅是在2020年,据估计用户将大约87%的在线时间用于移动应用程序,也就是手机的Ap ...

  4. android手机应用程序开发,Android手机应用程序开发标准

    模块测试点应用程序apk,屏幕快照和图标,名称,类别,作者,应用程序apk,屏幕快照和图标,名称,类别,作者,完整性适配固件屏幕,功能介绍,授权区域,促销的预期结果配备带有固件屏幕,功能介绍,授权区域 ...

  5. android 游戏 锁屏界面开发,android 锁屏程序开发

    参考http://blog.csdn.net/wdaming1986/article/details/8837023 锁屏程序的步骤如下: 1.替换系统锁屏 2.屏蔽Home键,back键.menu键 ...

  6. Android物联网应用程序开发(智慧园区)—— 图片预览界面

    效果图: 实现步骤: 1.首先在 build.gradle 文件中引入 RecycleView implementation 'com.android.support:recyclerview-v7: ...

  7. Android手机拍照程序开发,android Camera开发-手机拍照流程

    android 拍照API流程 1. 在布局文件中添加一个 surfaceView (摄影平面) 2.根据 SurfaceView  获得 Holder (固定器) 3.给固定器设置 SurfaceH ...

  8. Android移动应用程序开发

    Log类 直接调用静态方法输出调试信息,在"Logcat"窗口中输出,并可以通过过滤器对<tag>标签进行筛选."Logcat"窗口中输出的调试信息 ...

  9. 【241期门诊集锦】正确高效的Android应用程序开发

    技术门诊是51CTO社区品牌栏目,每周邀请一位客座专家,为广大技术网友解答疑问.从热门技术到前沿知识,从技术答疑到职业规划.每期一个主题,站在最新最热的技术前沿为你引航! 本期特邀<Androi ...

最新文章

  1. 管道:介绍和基本服务
  2. ML之LoR:LoR之二分类之线性决策算法实现根据两课成绩分数~预测期末通过率(合格还是不合格)
  3. Kubernetes通过containerd访问registry的30443端口
  4. [NHibernate]获取分组查询的记录总数
  5. 关于CSS预处理器(less,sass)
  6. 使用php语言 统计字符串,php如何查询字符串长度
  7. 关于并查集的Python实现代码
  8. Latex中导入VISIO图片
  9. 如何将汇编语言转换为c语言,如何把汇编语言转换成C语言
  10. 基于Neo4j计算网络节点中心性(Closeness、betweenness Centrality)
  11. 计算机管理调整磁盘分区,win7系统硬盘分区调整方法图解
  12. Dos命令查看wifi密码
  13. Lucene学习总结之一:全文检索的基本原理
  14. echarts踩坑记录---仪表盘设置仪表盘的位置
  15. Android默认时区、语言设置
  16. 完美解决python manage.py makemigrations 报错
  17. python学习笔记3
  18. iphone各个系列手机最新的尺寸资料(更新到iphone6s)
  19. 聪明人的游戏提高篇:贝贝的数学课 (change)
  20. STM32控制HC-05蓝牙模块进行通信

热门文章

  1. 官网下载Tomcat教程
  2. 如何打造自己的个人移动知识库?不妨试试这个工具软件
  3. 《嵌入式 – GD32开发实战指南》第20章 GD32的存储结构
  4. Luogu P1365 WJMZBMR打osu! / Easy
  5. [洛谷 1365] WJMZBMR打osu! / Easy {期望DP}
  6. 深圳大学计算机学硕毕业条件,深圳大学硕士研究生奖助体系(2020级)
  7. 李航《统计学习方法》第2版 第10章 HMM实现分词(代码实现)
  8. flash和H5播放器
  9. innosetup打包驱动
  10. 刻意练习-如何从新手到大师