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币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- C183579-123578-c1235789.jpg
- Qt5.14 绘画板 Qt Creator C++项目
- python实现Excel表格合并
- Java实现读取Excel批量发送邮件.zip
- 【java毕业设计】商城后台管理系统源码(springboot+vue+mysql+说明文档).zip
- 【java毕业设计】开发停车位管理系统(调用百度地图API)源码(springboot+vue+mysql+说明文档).zip
- 星耀软件库(升级版).apk.1
- 基于Django后端和Vue前端的多语言购物车项目设计源码
- 基于Python与Vue的浮光在线教育平台源码设计
- 31129647070291Eclipson MXS R.zip
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功