java实现一个socks5代理 <一>了解nio Selector的基本用法
来源:互联网 发布:阿里云备案管理系统 编辑:程序博客网 时间:2024/06/06 11:02
上面浏览器可以放心的将数据交给代理了,接下来做的是怎样处理这些数据,以及面对浏览器突然过来的很多连接如何处理他们,这就要用到javax.nio包下的东西了,下面做简单介绍,不会nio可以先去学习下nio selector的基本用法,再回来接着看,下面先讲思路再上代码
1.创建ServiceSocketChannel,监听在5661端口。
2.像selector注册accept事件
3.堵塞式的从selector选择,选择后就开始执行
4.允许所有的连接,对获取到的连接都发送 5 0 表示接受无密码的连接
5.接受到ip port 的信息后,ip port 解析出来,异步连接到此ip port 并注册 connection事件
6。当连接事件触发后,完成连接,像浏览器返回 连接成功的标识。
7.像selector注册两个监听,分别监听client 和 外网 的socketchannel连接 read事件
8.当监听到其中一方的数据就读取并将数据写入另一方的channel中。
9.当读到流的末尾,管理连接,注销掉channel 等。
10.socks4的握手方式和socks5不同其他都相同,所以可以共用大部分代码
package com.proxydemo;import java.io.IOException;public class Main {//程序启动入口public static void main(String[] args) throws IOException {Reactor reactor=new Reactor();reactor.run();}}
package com.proxydemo;/*
容器类,selector的创建 以及做选择 并且执行的类
*/import java.io.IOException;import java.net.InetSocketAddress;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.util.Iterator;import java.util.Set;//容器类public class Reactor implements Runnable {private Selector selector;//容器private ServerSocketChannel ssc;//服务端socketchannelpublic Reactor() throws IOException{//初始化容器和服务器selector=Selector.open();ssc=ServerSocketChannel.open();//绑定事件 和 端口 设置异步ssc.bind(new InetSocketAddress(5661));ssc.configureBlocking(false);SelectionKey key = ssc.register(selector, SelectionKey.OP_ACCEPT);//创建accept事件,以及创建处理的线程key.attach(new AcceptAcceptor(selector,ssc));
}public void run() {while(true){try {int size = selector.select();if(size==0){continue;}} catch (IOException e) {e.printStackTrace();}Set<SelectionKey> keys = selector.selectedKeys();Iterator<SelectionKey> iterator = keys.iterator();while(iterator.hasNext()){SelectionKey next = iterator.next();consume(next);iterator.remove();}}}private void consume(SelectionKey key){Runnable r = (Runnable) key.attachment();r.run();}}
package com.proxydemo;import java.io.IOException;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;//负责接受连接的类,接受完立即注册 读操作 读操作出发 Handler551public class AcceptAcceptor implements Runnable {private Selector selector;private ServerSocketChannel ssc;public AcceptAcceptor(Selector selector,ServerSocketChannel ssc){this.selector=selector;this.ssc=ssc;}public void run() {try {SocketChannel socket = ssc.accept();socket.configureBlocking(false);SelectionKey keyclient = socket.register(selector, SelectionKey.OP_READ);keyclient.attach(new Handler551(keyclient));} catch (IOException e) {e.printStackTrace();}}}
package com.proxydemo;import java.io.IOException;import java.net.InetAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;import java.util.Arrays;/*出发了读操作触发此事件 目的读取 5 1 0 /或者4 1 0 * 出发写操作的事件,目的写入 5 0 * 根据事件的不同做出不同行为
根据是socks4 /socks5做不同处理 * */public class Handler551 implements Runnable {private Selector selector;private SocketChannel sc;private SelectionKey keyclient;private ByteBuffer bytebuffer=ByteBuffer.allocate(10);static byte bb510[]={5,0};static byte bb410[]={0,90,0,0,0,0,0,0}; //返回愿意连接public Handler551(SelectionKey keyclient){this.selector=keyclient.selector();this.keyclient=keyclient;sc=(SocketChannel) keyclient.channel();}public void run() {bytebuffer.clear();try {int read = sc.read(bytebuffer);if(read==-1){keyclient.cancel();return;}System.out.println("得到的结果"+Arrays.toString(bytebuffer.array()));int b = bytebuffer.get(0);if(b==5){ //协议5sc.write(ByteBuffer.wrap(bb510));keyclient.attach(new Handler501002( keyclient));}else if(b==4){//协议4int portflag=bytebuffer.get(2);int port=bytebuffer.get(3);if(port>0){port=256*portflag+port;}else{port=256*portflag+(256+port);}StringBuilder sb=new StringBuilder();int A=bytebuffer.get(4);int B=bytebuffer.get(5);int C=bytebuffer.get(6);int D=bytebuffer.get(7);System.out.println("原来的"+A+"."+B+"."+C+"."+D);if(A<0) A=256+A;if(B<0) B=256+B;if(C<0) C=256+C;if(D<0) D=256+D;sb.append(A);sb.append(".");sb.append(B);sb.append(".");sb.append(C);sb.append(".");sb.append(D);String host=sb.toString();sc.write(ByteBuffer.wrap(bb410));keyclient.attach(new Sockts4Handler( keyclient,host,port));}} catch (IOException e) {keyclient.cancel();selector.wakeup();e.printStackTrace();}}}
package com.proxydemo;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;/* * 第一步初步握手完成后 第二步 进行验证握手 如果是socks5 则执行这一步 进行接受ip和端口信息 * */public class Handler501002 implements Runnable {private Selector selector;private SocketChannel sc;private SelectionKey keyclient;static byte bb501002[]={5,0,0,1,0,0,0,0,1,1};ByteBuffer bytebuffer=ByteBuffer.allocate(100);public Handler501002(SelectionKey keyclient){this.selector=keyclient.selector();this.keyclient=keyclient;this.sc=(SocketChannel) keyclient.channel();}/*1.读取数据 * 2.解析数据,建立连接,绑定下一个handler * * */public void run() {int read=-1;try {read = sc.read(bytebuffer);} catch (IOException e) {e.printStackTrace();}if(read==-1){keyclient.cancel();return;}//sc.write(ok50001);//2.解析数据String host=getHost(bytebuffer.asReadOnlyBuffer(), read);int port=getPort(bytebuffer.asReadOnlyBuffer(), read);try{//4.不处理host为空的数据if(host==null||"".equals(host)){for(int i=0;i<read;i++){//***********************System.out.print(bytebuffer.get(i));System.out.println("host null");}sc.close();keyclient.cancel();selector.wakeup();return;}//3.创建channelSocketChannel scClient=SocketChannel.open();//5 不处理查找不到ip地址的域名InetSocketAddress isa=new InetSocketAddress(host, port);if(isa.isUnresolved() || isa.getAddress().equals("") ||isa.getAddress().equals("127.0.0.1")){sc.close();keyclient.cancel();return;}//5.设置异步scClient.configureBlocking(false);//6.异步连接scClient.connect(isa);//7.注册SelectionKey register = scClient.register(selector, SelectionKey.OP_CONNECT);//7 还没有连接上时 暂时不监测client、的是否有东西可读keyclient.interestOps(keyclient.interestOps() &~SelectionKey.OP_READ );//8添加连接事件/* 分别是与优酷之间的连接 || 与client之间的连接 */register.attach(new LinkFinish( register,keyclient)); //传进去代理和优酷之间的连接System.out.println(host+":"+port);}catch(IOException e){e.printStackTrace();}}//解析地址public String getHost(ByteBuffer a,int len){if(len<8){return null;}StringBuffer sb=new StringBuffer();if(a.get(3)==3){//说明是网址地址int size=a.get(4); //网址长度for(int i=5;i<(5+size);i++){sb.append((char)a.get(i));}}else if(a.get(3)==1){//说明是ip地址for(int i=4;i<=7;i++){int A=a.get(i);if(A<0) A=256+A;sb.append(A);sb.append(".");}sb.deleteCharAt(sb.length()-1);}return sb.toString();}//解析端口public int getPort(ByteBuffer a,int len){if(len<4){return 0;}int port = a.get(len-1);int thod=a.get(len-2);if(port>0){return 256*thod+port;}else{return 256*thod +(256+port);}}}
package com.proxydemo;import java.io.IOException;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;import java.util.concurrent.TimeoutException;/* * 异步连接如果触发,则完成连接,注册读取事件 上一步获取了真正的ip和port并进行异步连接,这一步完成真正的连接* */public class LinkFinish implements Runnable {static byte bb501002[]={5,0,0,1,0,0,0,0,1,1};private Selector selector;private SocketChannel sc; //代理和实际网站的连接private SocketChannel cd; //client和代理之间private SelectionKey key551,keyWeb;public LinkFinish(SelectionKey keyWeb,SelectionKey key551){this.selector=key551.selector();this.key551=key551;this.keyWeb=keyWeb;sc=(SocketChannel) keyWeb.channel();cd=(SocketChannel) key551.channel();}public void run() {//1.完成连接boolean finishConnect =false;try {finishConnect = sc.finishConnect();//1 向客户端通知他连接成功了,可以发送数据了ByteBuffer ok50001 = ByteBuffer.wrap(bb501002);//返回愿意连接cd.write(ok50001);if(finishConnect){//2.转换成read//keyFor.interestOps(SelectionKey.OP_READ &~SelectionKey.OP_CONNECT);keyWeb.interestOps(keyWeb.interestOps() & 0 |SelectionKey.OP_READ);key551.interestOps(SelectionKey.OP_READ );//3.切换handlerkeyWeb.attach(new ReadHandler(keyWeb,key551));//设置Handler 代理to优酷 电脑to代理key551.attach(new ReadHandler2( keyWeb,key551));//代理to优酷 电脑to代理System.out.println("实际连接");//selector.wakeup();}} catch (IOException e1) {try {sc.close();cd.close();} catch (IOException e) {e.printStackTrace();}keyWeb.cancel();key551.cancel();System.out.println("超时一个"+sc.socket().getInetAddress());//selector.wakeup();return;}}}
package com.proxydemo;import java.io.IOException;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;import java.util.Arrays;/* * 代理将数据打向浏览器 * */public class ReadHandler implements Runnable {private Selector selector;private SocketChannel sc; //代理和优酷网站之间的通道private SocketChannel cd;//浏览器和代理之间的通道private SelectionKey key551,keyWeb;ByteBuffer buffer=ByteBuffer.allocate(6144);public ReadHandler(SelectionKey keyWeb,SelectionKey key551){this.selector=key551.selector();this.keyWeb=keyWeb;this.key551=key551;sc=(SocketChannel) keyWeb.channel();cd=(SocketChannel) key551.channel();}/*负责交换数据,都的话放进缓冲区,写的话,从缓冲区中国写 * */public void run() {//ByteBuffer buffer=ByteBuffer.allocate(4096); //浏览器打向代理//1.清空缓冲区buffer.clear();//2.读取数据int read=-1;try {read = sc.read(buffer);} catch (IOException e1) {/*异常则证明连接已经断开了,直接断开就可以*/e1.printStackTrace();}//检查是否是-1 是的话说明没有数据读 或者已经关闭了if(read==-1){//没关闭就将他关闭if(sc.isOpen()){try {sc.close();} catch (IOException e) {e.printStackTrace();}}keyWeb.cancel();return;//selector.wakeup();}int write=-1;if(read>0){buffer.flip();if(cd.isOpen()){try { write = cd.write(buffer);} catch (IOException e) {e.printStackTrace();}}}if(write==-1){if(cd.isOpen()){try {cd.close();} catch (IOException e) {e.printStackTrace();}key551.cancel();}}buffer.clear();if(read==0){//keyFor2.interestOps(SelectionKey.OP_WRITE);//selector.wakeup();}System.out.println(read+"接收");}}
package com.proxydemo;import java.io.IOException;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;//浏览器将数据打向代理//public class ReadHandler2 implements Runnable {private Selector selector;private SocketChannel sc; //代理和优酷网站之间的通道private SocketChannel cd;//浏览器和代理之间的通道private SelectionKey key551,keyWeb;ByteBuffer buffer=ByteBuffer.allocate(6144);public ReadHandler2(SelectionKey keyWeb,SelectionKey key551){this.selector=key551.selector();this.keyWeb=keyWeb;this.key551=key551;this.sc=(SocketChannel) keyWeb.channel();this.cd=(SocketChannel) key551.channel();}/*负责交换数据,都的话放进缓冲区,写的话,从缓冲区中国写 * */public void run() {//ByteBuffer buffer=ByteBuffer.allocate(10240);//1.清空缓冲区buffer.clear();//2.读取数据int read=-1;if(cd.isOpen()){try {read = cd.read(buffer);} catch (IOException e) {e.printStackTrace();}}if(read==-1){if(cd.isOpen()){try {cd.close();} catch (IOException e) {e.printStackTrace();}}key551.cancel();return;}int write=-1;if(read>0){buffer.flip();if(cd.isOpen()){try {write = sc.write(buffer);} catch (IOException e) {e.printStackTrace();}}}if(write==-1){if(cd.isOpen()){try {cd.close();} catch (IOException e) {e.printStackTrace();}}keyWeb.cancel();}buffer.clear();if(read==0){//keyFor.interestOps(SelectionKey.OP_WRITE);//selector.wakeup();}System.out.println("发送"+read);}}
package com.proxydemo;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;//如果是sockets4 则执行这个public class Sockts4Handler implements Runnable {private Selector selector;private SocketChannel sc;private SelectionKey keyclient;String host;int port;public Sockts4Handler(SelectionKey keyclient,String host,int port){this.selector=keyclient.selector();this.keyclient=keyclient;this.sc=(SocketChannel) keyclient.channel();this.host=host;this.port=port;}/*1.读取数据 * 2.解析数据,建立连接,绑定下一个handler * * */public void run() {try{//4.不处理host为空的数据if(host==null||"".equals(host)){sc.close();keyclient.cancel();selector.wakeup();return;}//3.创建channelSocketChannel scClient=SocketChannel.open();//5 不处理查找不到ip地址的域名InetSocketAddress isa=new InetSocketAddress(host, port);if(isa.isUnresolved() || isa.getAddress().equals("") ||isa.getAddress().equals("127.0.0.1")){sc.close();keyclient.cancel();return;}//5.设置异步scClient.configureBlocking(false);//6.异步连接scClient.connect(isa);//7.注册SelectionKey register = scClient.register(selector, SelectionKey.OP_CONNECT);//7 还没有连接上时 暂时不监测client、的是否有东西可读keyclient.interestOps(keyclient.interestOps() &~SelectionKey.OP_READ );//8添加连接事件/* 分别是与优酷之间的连接 || 与client之间的连接 */register.attach(new Sockets4LinkFinish( register,keyclient)); //传进去代理和优酷之间的连接System.out.println(host+":"+port);}catch(IOException e){e.printStackTrace();}}}
package com.proxydemo;import java.io.IOException;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;import java.util.concurrent.TimeoutException;/* * 异步连接如果触发,则完成连接,注册读取事件 sockets4 执行这个* */public class Sockets4LinkFinish implements Runnable {static byte bb501002[]={5,0,0,1,0,0,0,0,1,1};static byte bb401002[]={0,90,0,0,0,0,0,0};private Selector selector;private SocketChannel sc; //代理和实际网站的连接private SocketChannel cd; //client和代理之间private SelectionKey key551,keyWeb;public Sockets4LinkFinish(SelectionKey keyWeb,SelectionKey key551){this.selector=key551.selector();this.key551=key551;this.keyWeb=keyWeb;sc=(SocketChannel) keyWeb.channel();cd=(SocketChannel) key551.channel();}public void run() {//1.完成连接boolean finishConnect =false;try {finishConnect = sc.finishConnect();//1 向客户端通知他连接成功了,可以发送数据了ByteBuffer ok50001 = ByteBuffer.wrap(bb401002);//返回愿意连接//cd.write(ok50001);if(finishConnect){//2.转换成read//keyFor.interestOps(SelectionKey.OP_READ &~SelectionKey.OP_CONNECT);keyWeb.interestOps(keyWeb.interestOps() & 0 |SelectionKey.OP_READ);key551.interestOps(SelectionKey.OP_READ );//3.切换handlerkeyWeb.attach(new ReadHandler(keyWeb,key551));//设置Handler 代理to优酷 电脑to代理key551.attach(new ReadHandler2( keyWeb,key551));//代理to优酷 电脑to代理System.out.println("实际连接");//selector.wakeup();}} catch (IOException e1) {try {sc.close();cd.close();} catch (IOException e) {e.printStackTrace();}keyWeb.cancel();key551.cancel();System.out.println("超时一个"+sc.socket().getInetAddress());//selector.wakeup();return;}}}
这个demo主要是练习下nio的使用,兼容socks4 后,可以将internate选项中设置套接字,那个直接就是socks4的代理,这样能看到很多数据包在代理中流动,本地使用对浏览器打开网页的速度影响非常小,几乎看不出来
阅读全文
0 0
- java实现一个socks5代理 <一>了解nio Selector的基本用法
- java实现一个socks5代理 <一>了解socks5协议
- JAVA NIO的selector的实现原理
- Java NIO之多个Selector的实现
- 基于netty实现的socks5代理协议
- 基于netty实现的socks5代理协议
- 使用java nio的selector做一个数据查询主机
- java nio selector的使用
- Java NIO 选择器(Selector)的内部实现(poll epoll)
- Java NIO 选择器(Selector)的内部实现(poll epoll)
- NIO:Selector 类用法
- JAVA NIO(一):Buffer.mark()的用法
- socks5反向代理实现思路
- java的selector用法
- 利用ssh的端口转发实现SOCKS5代理
- Java NIO 实现简单代理
- Nio--Selector实现简易的http服务器
- Nio--Selector实现简易的http服务器
- 如何将sde数据发布成featurelayer以后,能够用js操作数据
- Window 通过cmd查看端口占用、相应进程、杀死进程等的命令
- 初级篇 Eclipse+ssm简单配置
- Read-only file system问题的解决方法
- [vim]禁止生成un~文件
- java实现一个socks5代理 <一>了解nio Selector的基本用法
- csdn如何转载别人的博客
- 动态改变弹出框的内容
- 程序人生
- 线性筛素数
- java.util 时间操作之Date类
- Samba 企业应用案例
- 一步到位的学习网址---岁月中沉淀下来的小经验分享给大家
- Spark:Scala实现action操作