package org.example;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.example.common.HttpRequestParser;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
public class ServerEventLoop extends AbstractEventLoop {
private final Logger logger = LogManager.getLogger(ServerEventLoop.class);
public ServerEventLoop(Bootstrap bootstrap) {
super(bootstrap);
}
@Override
protected void processSelectedKey(SelectionKey key) {
if (key.isValid() && key.isAcceptable()) {
if (key.attachment() instanceof Acceptor acceptor) {
acceptor.accept();
}
}
if (key.isValid() && key.isReadable()) {
if (key.attachment() instanceof ChannelHandler channelHandler) {
channelHandler.handleRead();
}
}
if (key.isValid() && key.isConnectable()) {
key.interestOpsAnd(~SelectionKey.OP_CONNECT);
if (key.attachment() instanceof ChannelHandler channelHandler) {
channelHandler.handleConnect();
}
}
if (key.isValid() && key.isWritable()) {
key.interestOpsAnd(~SelectionKey.OP_WRITE);
if (key.attachment() instanceof ChannelHandler channelHandler) {
channelHandler.handleWrite();
}
}
}
@Override
public void bind(int port) throws Exception {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
SelectionKey key = serverSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT);
key.attach(new Acceptor(serverSocketChannel));
serverSocketChannel.bind(new InetSocketAddress(port));
}
class Acceptor {
ServerSocketChannel ssc;
public Acceptor(ServerSocketChannel ssc) {
this.ssc = ssc;
}
public void accept() {
try {
SocketChannel socketChannel = ssc.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ, new ClientChannelHandler(socketChannel));
logger.info("accept client connection");
} catch (IOException e) {
logger.error("accept error");
}
}
}
abstract class ChannelHandler {
Logger logger;
SocketChannel channel;
ByteBuffer writeBuffer;
public ChannelHandler(SocketChannel channel) {
this.logger = LogManager.getLogger(this.getClass());
this.channel = channel;
this.writeBuffer = null;
}
abstract void handleRead();
public void handleWrite() {
doWrite();
}
public abstract void onChannelClose();
public ByteBuffer doRead() {
ByteBuffer buffer = ByteBuffer.allocate(4096);
try {
int len = channel.read(buffer);
if (len == -1) {
logger.info("read end-of-stream, close channel {}", channel);
channel.close();
onChannelClose();
}
if (len > 0) {
buffer.flip();
}
} catch (IOException e) {
logger.error("read channel error");
try {
channel.close();
onChannelClose();
} catch (IOException ex) {
logger.error("close channel error.");
}
}
return buffer;
}
public void doWrite() {
if (writeBuffer != null) {
try {
while (writeBuffer.hasRemaining()) {
channel.write(writeBuffer);
}
} catch (IOException e) {
logger.error("write channel error.");
try {
channel.close();
onChannelClose();
} catch (IOException ex) {
logger.error("close channel error");
}
}
writeBuffer = null;
}
}
public void handleConnect() {
}
}
class ClientChannelHandler extends ChannelHandler {
HttpRequestParser requestParser;
private SelectableChannel proxyChannel;
public ClientChannelHandler(SocketChannel sc) {
super(sc);
this.channel = sc;
this.requestParser = new HttpRequestParser();
this.proxyChannel = null;
}
@Override
public void handleRead() {
if (requestParser.isParsed()) {
if (proxyChannel != null) {
SelectionKey proxyKey = proxyChannel.keyFor(selector);
if (proxyKey != null && proxyKey.isValid() && proxyKey.attachment() instanceof ProxyChannelHandler proxyHandler) {
//需要等待ProxyHandler的写入缓存为空后才可读取客户端的数据
if (proxyHandler.writeBuffer == null) {
ByteBuffer buffer = doRead();
if (buffer.hasRemaining() && proxyKey.isValid()) {
proxyHandler.writeBuffer = buffer;
proxyKey.interestOpsOr(SelectionKey.OP_WRITE);
}
}
}
}
} else {
ByteBuffer buffer = doRead();
requestParser.putFromByteBuffer(buffer);
if (requestParser.isParsed()) {
//连接到目标服务器
ByteBuffer buf = null;
if (requestParser.getMethod().equals(HttpRequestParser.HTTP_METHOD_CONNECT)) {
//回写客户端连接成功
SelectionKey clientKey = channel.keyFor(selector);
if (clientKey != null && clientKey.isValid() && clientKey.attachment() instanceof ClientChannelHandler clientHandler) {
clientHandler.writeBuffer = ByteBuffer.wrap((requestParser.getProtocol() + " 200 Connection Established\r\n\r\n").getBytes());
clientKey.interestOpsOr(SelectionKey.OP_WRITE);
}
} else {
//将缓存的客户端的数据通过代理转发
byte[] allBytes = requestParser.getAllBytes();
buf = ByteBuffer.wrap(allBytes);
}
this.proxyChannel = connect(requestParser.getAddress(), buf);
}
}
}
@Override
public void onChannelClose() {
try {
if (proxyChannel != null) {
proxyChannel.close();
}
} catch (IOException e) {
logger.error("close channel error");
}
}
private SocketChannel connect(String address, ByteBuffer buffer) {
String host = address;
int port = 80;
if (address.contains(":")) {
host = address.split(":")[0].trim();
port = Integer.parseInt(address.split(":")[1].trim());
}
SocketA
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
NioProxy.rar (61个子文件)
NioProxy
NioProxy.iml 307B
out
artifacts
NioProxy_Single_jar
NioProxy-Single.jar 2.16MB
.idea
jarRepositories.xml 1KB
uiDesigner.xml 9KB
artifacts
NioProxy_Single_jar.xml 609B
NioProxy_Double_jar.xml 609B
workspace.xml 5KB
misc.xml 606B
compiler.xml 591B
modules.xml 263B
.gitignore 50B
encodings.xml 478B
NioProxy-Double
pom.xml 1KB
src
test
java
main
resources
log4j2.xml 925B
META-INF
MANIFEST.MF 55B
java
org
example
eventloop
ClientEventLoop.java 2KB
ProxyEventLoop.java 3KB
AbstractEventLoop.java 3KB
handler
ProxyChannelHandler.java 2KB
ClientChannelHandler.java 3KB
ChannelHandler.java 3KB
common
HttpRequestParser.java 3KB
UnboundedByteBuffer.java 1KB
Main.java 296B
Bootstrap.java 1KB
target
classes
log4j2.xml 925B
org
example
eventloop
ClientEventLoop$Acceptor.class 2KB
AbstractEventLoop.class 3KB
ProxyEventLoop.class 3KB
ClientEventLoop.class 2KB
handler
ProxyChannelHandler.class 3KB
ClientChannelHandler.class 4KB
ChannelHandler.class 3KB
Bootstrap.class 2KB
Main.class 735B
common
HttpRequestParser.class 3KB
UnboundedByteBuffer.class 1KB
generated-sources
annotations
NioProxy-Single
pom.xml 1KB
src
test
java
TestProxy.java 2KB
main
resources
log4j2.xml 925B
META-INF
MANIFEST.MF 55B
java
org
example
AbstractEventLoop.java 2KB
common
HttpRequestParser.java 3KB
UnboundedByteBuffer.java 1KB
ServerEventLoop.java 11KB
Main.java 296B
Bootstrap.java 918B
target
classes
log4j2.xml 925B
META-INF
MANIFEST.MF 55B
org
example
AbstractEventLoop.class 3KB
ServerEventLoop$Acceptor.class 2KB
Bootstrap.class 2KB
ServerEventLoop$ClientChannelHandler.class 5KB
ServerEventLoop$ProxyChannelHandler.class 3KB
Main.class 735B
ServerEventLoop.class 3KB
common
HttpRequestParser.class 3KB
UnboundedByteBuffer.class 1KB
ServerEventLoop$ChannelHandler.class 2KB
test-classes
TestProxy.class 3KB
generated-test-sources
test-annotations
generated-sources
annotations
logs
debug.log 12.09MB
共 61 条
- 1
资源评论
Yuriey
- 粉丝: 9
- 资源: 4
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- mysql安装包(5+8)
- (177718424)java飞机订票系统.zip
- 基于springboot的高校体测网络平台的设计源码(java毕业设计完整源码+LW).zip
- (177840612)基于平台的车道线检测.zip
- Java毕设项目:基于spring+mybatis+maven+mysql实现的校园活动管理平台【含源码+数据库+答辩PPT+任务书+毕业论文】
- 基于springboot的测试项目管理平台源码(java毕业设计完整源码+LW).zip
- 新年主题HTML页面设计指南
- 基于Springboot的BUG管理平台源码(java毕业设计完整源码+LW).zip
- 基于uniapp+springboot物流配送系统源码(java毕业设计完整源码).zip
- 基于曼宁公式求解复式断面水位-流量关系曲线(MATLAB全代码)
- 基于曼宁公式求解复式断面水位-流量关系曲线(MATLAB全代码)
- 圣诞节主题策划方案精选
- 机器学习(预测模型):合成代谢类固醇(AAS)使用情况的数据集
- 基于springboot的药品智能推荐系统的设计与实现源码(java毕业设计完整源码).zip
- 基于uniapp+springboot兼职app源码(java毕业设计完整源码).zip
- matlab2020从入门到精通-pdf
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功