java socket实现代理Android App
实现逻辑就是转发请求和响应。
核心代码
// 启动代理服务器private void startProxyServer() {new Thread(new ProxyServer()).start();}// 代理服务器static class ProxyServer implements Runnable {@Overridepublic void run() {try {// 监听指定的端口int port = 8098; //一般使用49152到65535之间的端口ServerSocket server = new ServerSocket(port);// 当一个ServerSocket关闭并释放其绑定的端口后,操作系统通常会在几分钟内不允许其他Socket再次绑定到该端口。// true:操作系统将允许其他Socket立即绑定到刚刚被释放的端口。server.setReuseAddress(true);// 使用线程池,防止过多线程耗尽资源ExecutorService threadPool = Executors.newFixedThreadPool(50);while (true) {Socket socket = server.accept(); //会一直阻塞,直到有客户端连接进来// new Thread 只是创建一个类的对象实例而已。而真正创建线程的是start()方法。// 这里并没有直接调用start()方法,所以并没创建新线程,而是交给线程池去执行。threadPool.submit(new ProxyClient(socket));}} catch (Exception e) {Log.e("ProxyServer", e.getMessage(), e);}}}// 代理客户端static class ProxyClient implements Runnable {private final Socket proxySocket;//代理Socketprivate Socket targetSocket = null;//目标Socketpublic ProxyClient(Socket socket) {this.proxySocket = socket;}@Overridepublic void run() {try {//客户端请求的报文InputStream req = proxySocket.getInputStream();int read;int contentLength = 0;//body长度String method = null;//请求方法String url = null;//请求地址String protocol = null;//请求协议ByteArrayOutputStream os = new ByteArrayOutputStream();ByteArrayOutputStream reqBack = new ByteArrayOutputStream();//解析,提取请求报文while ((read = req.read()) != -1) {os.write(read);reqBack.write(read);if (read == '\n') {//CONNECT www.xx.com:443/xx/yy HTTP/1.1String line = os.toString("UTF-8");os.reset();//重置,以便再次使用if ("\r\n".equals(line)) {//空行,请求头结束标志break;}StringTokenizer stringTokenizer = new StringTokenizer(line, " ");if (method == null) {//八种请求方法:GET、POST、HEAD、OPTIONS、PUT、PATCH、DELETE、TRACE、CONNECT 方法method = stringTokenizer.nextToken().toLowerCase();//connecturl = stringTokenizer.nextToken();//www.xx.com:443/xx/yyprotocol = stringTokenizer.nextToken().trim();//HTTP/1.1} else {String key = stringTokenizer.nextToken().toLowerCase();if ("content-length:".equals(key)) {String value = stringTokenizer.nextToken().trim();contentLength = Integer.parseInt(value);}}}}if (contentLength > 0) {for (int i = 0; i < contentLength; i++) {reqBack.write(req.read());}}//完整请求报文// String request = reqBack.toString("UTF-8");// System.out.println("请求报文开始");// System.out.print(request);// System.out.println("\r\n请求报文结束");//拼接完整urlif (url != null && !url.startsWith("http")) {url = method.equals("connect") ? "https://" + url : "http://" + url;}URL u = new URL(url);//目标ipString targetHost = u.getHost();//目标端口int targetPort = u.getPort();if (targetPort == -1) {targetPort = 80;}//目标SockettargetSocket = new Socket(targetHost, targetPort);if ("connect".equals(method)) {//https//HTTP/1.1 200 Connection established//报文直接发送给代理SocketOutputStream outputStream = proxySocket.getOutputStream();outputStream.write((protocol + " 200 Connection established\r\n").getBytes(StandardCharsets.UTF_8));outputStream.write("Proxy-agent: ProxyServer/1.0\r\n".getBytes(StandardCharsets.UTF_8));outputStream.write("\r\n".getBytes(StandardCharsets.UTF_8));outputStream.flush();//前者转发给后者,代理Socket转发给目标SocketThread proxy2target = new Thread(new ForwardData(proxySocket, targetSocket));proxy2target.start();//前者转发给后者,目标Socket转发给代理SocketThread target2proxy = new Thread(new ForwardData(targetSocket, proxySocket));target2proxy.start();proxy2target.join();} else {//http//请求报文转发给目标SocketOutputStream outputStream = targetSocket.getOutputStream();outputStream.write(reqBack.toByteArray());outputStream.flush();//前者转发给后者,目标Socket转发给代理SocketThread thread = new Thread(new ForwardData(targetSocket, proxySocket));thread.start();thread.join();}} catch (Exception e) {Log.e("ProxyClient", e.getMessage(), e);} finally {try {if (targetSocket != null) {targetSocket.close();}} catch (IOException e) {Log.e("ProxyClient", e.getMessage(), e);}try {if (proxySocket != null) {proxySocket.close();}} catch (IOException e) {Log.e("ProxyClient", e.getMessage(), e);}}// Log.e("ProxyClient", "结束");}// 转发数据static class ForwardData implements Runnable {private final Socket inputSocket;private final Socket outputSocket;public ForwardData(Socket inputSocket, Socket outputSocket) {this.inputSocket = inputSocket;this.outputSocket = outputSocket;}@Overridepublic void run() {try {InputStream inputStream = inputSocket.getInputStream();OutputStream outputStream = outputSocket.getOutputStream();int read;while ((read = inputStream.read()) != -1) {outputStream.write(read);}} catch (Exception e) {// Log.e("ForwardData", inputSocket + e.getMessage());}}}}
app源码
proxyserver: 代理服务器app
我已打包,打包地址:https://gitee.com/gloweds/proxyserver/raw/master/app/release/app-release.apk
有时会报错,但是这个错误不影响功能。
报错时间线如下:
2023-10-06 11:29:16.478 客户端请求结束(发起http请求)
2023-10-06 11:29:16.555 代理proxySocket的read()报错 Connection reset
2023-10-06 11:29:16.571 关闭两个Socket连接
2023-10-06 11:29:16.571 目标targetSocket的read()报错 Socket closed
上面报错的原因,是因为客户端请求发送报文没有完整发送结束标识-1,
如果客户端完整发送结束标识,上面的两个错误不会发生(Connection reset、Socket closed),但是这个错误不影响功能,可以不用处理。
代理proxySocket的read()报错 Connection reset,是因为客户端未完整发送结束标识-1,而客户端请求都结束了,也成功拿到了响应数据,这时关闭连接就导致代理proxySocket的read()报错 Connection reset。
目标targetSocket的read()报错 Socket closed,因为前面代理proxySocket的read()阻塞未正常发送结束标识,所以targetSocket的read()也阻塞了,关闭两个proxySocket和targetSocket连接后,targetSocket的read()自然报错Socket closed连接被强制关闭了。
https请求流程图:
相关文章:

java socket实现代理Android App
实现逻辑就是转发请求和响应。 核心代码 // 启动代理服务器private void startProxyServer() {new Thread(new ProxyServer()).start();}// 代理服务器static class ProxyServer implements Runnable {Overridepublic void run() {try {// 监听指定的端口int port 8098; //一…...

Nacos与Eureka的区别
大家好我是苏麟今天说一说Nacos与Eureka的区别. Nacos Nacos的服务实例分为两种l类型: 临时实例:如果实例宕机超过一定时间,会从服务列表剔除,默认的类型。非临时实例:如果实例宕机,不会从服务列表剔除&…...
浅谈Rob Pike的五条编程规范
又是一篇需要我们多些思考的文章~ 简介下Rob Pike Rob Pike是Unix的先驱,UTF-8的设计人,Go语言核心设计者之一。 Rob Pike的5条编程规则 原文地址:http://users.ece.utexas.edu/~adnan/pike.html 中文翻译: 罗布派克&#x…...

LeetCode 377.组合总和IV 可解决一步爬m个台阶到n阶楼顶问题( 完全背包 + 排列数)
给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。 题目数据保证答案符合 32 位整数范围 示例 1: 输入:nums [1,2,3], target 4 输出:7 解释&#x…...

C中volatile总结
在CPU处理过程中,需要将内存中的数据载入到寄存器中才能计算,所以可能涉及到一个问题,如果内存中的数据被更改了,但是寄存器还是使用的旧数据,这样就会造成数据的不同步。 一、volatile关键字的作用 使用volatile关键…...

asp.net班级管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio
一、源码特点 asp.net班级管理系统 是一套完善的web设计管理系统,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为vs2010,数据库为sqlserver2008,使用c#语言开发 asp.net班级管理系统 二、功能介绍 1…...

【Pytorch笔记】6.Transforms
pytorch官方文档 - transforms transforms需要使用计算机视觉工具包:torchvision。 torchvision.transforms:常用的图像预处理方法; torchvision.datasets:常用数据集的dataset实现,如MNIST、CIFAR-10、ImageNet等&am…...

nodejs+vue临沂特色产品销售平台elementui
从实际工作出发,对过去的临沂特色产品销售平台存在的问题进行分析,完善用户的使用体会。采用计算机系统来管理信息 提高了工作的效率。 随着信息化社会的形成和微电子技术日新月异的发展,临沂特色产品销售平台是针对目前临沂特色产品销售…...
机器学习必修课 - 使用管道 Pipeline
目标:学习使用管道(pipeline)来提高机器学习代码的效率。 1. 运行环境:Google Colab import pandas as pd from sklearn.model_selection import train_test_split!git clone https://github.com/JeffereyWu/Housing-prices-dat…...

WEB各类常用测试工具
一、单元测试/测试运行器 1、Jest 知名的 Java 单元测试工具,由 Facebook 开源,开箱即用。它在最基础层面被设计用于快速、简单地编写地道的 Java 测试,能自动模拟 require() 返回的 CommonJS 模块,并提供了包括内置的测试环境 …...
Naive UI 文档地址
最近几天官网访问不了,自己用github pages 部署了个 官网 github pages...
在CentOS7系统中安装MySQL5.7
第一步:下载MySQL包 > wget http://repo.mysql.com/mysql57-community-release-el7-10.noarch.rpm第二步:安装MySQL源 > rpm -Uvh mysql57-community-release-el7-10.noarch.rpm第三步:安装MySQL服务端 > yum install -y mysql-c…...

R语言通过接口获取网上数据平台的免费数据
大家好,我是带我去滑雪! 作为一名统计学专业的学生,时常和数据打交道,我深知数据的重要性。数据是实证研究的重要基础,每当在完成一篇科研论文中的实证研究部分时,我都能深刻体会实证研究最复杂、最耗时的工…...

【Docker内容大集合】Docker从认识到实践再到底层原理大汇总
前言 那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助。 高质量博客汇总https://blog.csdn.net/yu_cblog/categ…...

算法题:摆动序列
这道题是一道贪心算法题,如果前两个数是递增,则后面要递减,如果不符合则往后遍历,直到找到符合的。(完整题目附在了最后) 代码如下: class Solution(object):def wiggleMaxLength(self, nums):…...

复习 --- QT服务器客户端
服务器: 头文件: #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QTcpServer> #include<QTcpSocket> #include<QMessageBox> #include<QDebug> #include<QList> #include<QListWidget> #in…...

Godot 官方2D游戏笔记(1):导入动画资源和添加节点
前言 Godot 官方给了我们2D游戏和3D游戏的案例,不过如果是独立开发者只用考虑2D游戏就可以了,因为2D游戏纯粹,我们只需要关注游戏的玩法即可。2D游戏的美术素材简单,交互逻辑简单,我们可以把更多的时间放在游戏的玩法…...
leetcode 热题 100
数组和字符串匹配 子串和子序列 原串:“abcabc” 子串:“abc”, 连续但不大于原串的字符串 子序列:“acc”, 字符来自原串且保持在原串中顺序不变的字符串 子排列: “aabbcc”, 字符来自原串且只能用1次,但可有不同排列顺序的字…...

Ae 效果:CC Lens
扭曲/CC Lens Distort/CC Lens CC Lens (CC 镜头)主要用于添加或移除摄像机镜头扭曲,比如桶形失真 Barrel、枕形失真 Pincushion以及鱼眼失真 Fisheye等。或者,用它来创建一些特殊的动画效果。 ◆ ◆ ◆ 效果属性说明 Center 中…...

【Redis】基础数据结构-quicklist
Redis List 在Redis3.2版之前,Redis使用压缩列表和双向链表作为List的底层实现。当元素个数比较少并且元素长度比较小时,Redis使用压缩列表实现,否则Redis使用双向链表实现。 ziplist存在问题 不能保存过多的元素,否则查找复杂度…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...

GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...