上面浏览器可以放心的将数据交给代理了,接下来做的是怎样处理这些数据,以及面对浏览器突然过来的很多连接如何处理他们,这就要用到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; //服务端socketchannel
public 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;
//负责接受连接的类,接受完立即注册 读操作 读操作出发 Handler551
public 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
* 根据事件的不同做出不同行为