Files
KLALB/src/org/kne/cloud/network/BufferedChannel.java
T
2025-11-15 11:08:16 +08:00

445 lines
14 KiB
Java

package org.kne.cloud.network;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
/**
* 修复的BufferedChannel,解决Socket关闭时的数据一致性问题
*/
public class BufferedChannel implements ReadableByteChannel, WritableByteChannel, ScatteringByteChannel, GatheringByteChannel {
private final ReadableByteChannel inputChannel;
private final WritableByteChannel outputChannel;
private final ByteBuffer readBuffer;
private final ByteBuffer writeBuffer;
private final ReentrantLock readLock = new ReentrantLock();
private final ReentrantLock writeLock = new ReentrantLock();
private final AtomicBoolean closed = new AtomicBoolean(false);
private final AtomicBoolean inputShutdown = new AtomicBoolean(false);
private final AtomicBoolean outputShutdown = new AtomicBoolean(false);
public BufferedChannel(ReadableByteChannel channel, int bufferSize) {
this(channel, null, bufferSize);
}
public BufferedChannel(WritableByteChannel channel, int bufferSize) {
this(null, channel, bufferSize);
}
public BufferedChannel(ReadableByteChannel inputChannel, WritableByteChannel outputChannel, int bufferSize) {
this.inputChannel = inputChannel;
this.outputChannel = outputChannel;
this.readBuffer = ByteBuffer.allocateDirect(bufferSize);
this.writeBuffer = ByteBuffer.allocateDirect(bufferSize);
// 更安全的初始化
this.readBuffer.limit(0); // 明确设置为空
this.writeBuffer.clear();
}
@Override
public int read(ByteBuffer dst) throws IOException {
if (closed.get() || inputShutdown.get()) {
throw new ClosedChannelException();
}
readLock.lock();
try {
// 检查底层通道是否仍然打开
if (inputChannel != null && !inputChannel.isOpen()) {
inputShutdown.set(true);
return handleInputShutdown();
}
int totalRead = 0;
boolean eofEncountered = false;
while (dst.hasRemaining() && !eofEncountered) {
// 如果读缓冲区有数据,先从中读取
if (readBuffer.hasRemaining()) {
int bytesToCopy = Math.min(readBuffer.remaining(), dst.remaining());
// 使用绝对位置操作,避免修改缓冲区状态
int oldlimit=readBuffer.limit();
readBuffer.limit(readBuffer.position()+bytesToCopy);
dst.put(readBuffer);
readBuffer.limit(oldlimit);
totalRead += bytesToCopy;
continue;
}
// 读缓冲区空了,需要重新填充
readBuffer.clear();
int bytesRead;
try {
bytesRead = inputChannel.read(readBuffer);
} catch (IOException e) {
// 读取时发生IO异常,标记为关闭
inputShutdown.set(true);
throw e;
}
if (bytesRead == -1) {
// 到达EOF
inputShutdown.set(true);
eofEncountered = true;
} else if (bytesRead == 0) {
// 没有数据可用,可能是非阻塞模式
break;
} else {
readBuffer.flip();
}
}
// 如果遇到EOF且没有读取到任何数据,返回-1
if (eofEncountered && totalRead == 0) {
return -1;
}
return totalRead;
} finally {
readLock.unlock();
}
}
/**
* 处理输入关闭的情况
*/
private int handleInputShutdown() throws IOException {
// 如果读缓冲区还有剩余数据,先返回这些数据
if (readBuffer.hasRemaining()) {
return readBuffer.remaining();
}
return -1;
}
@Override
public long read(ByteBuffer[] dsts) throws IOException {
return read(dsts, 0, dsts.length);
}
@Override
public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
if (closed.get() || inputShutdown.get()) {
throw new ClosedChannelException();
}
long totalRead = 0;
for (int i = offset; i < offset + length; i++) {
ByteBuffer dst = dsts[i];
if (dst == null) {
throw new NullPointerException("Destination buffer is null");
}
int bytesRead = read(dst);
if (bytesRead == -1) {
// 只有在没有读取任何数据时才返回-1
return totalRead > 0 ? totalRead : -1;
}
totalRead += bytesRead;
}
return totalRead;
}
@Override
public int write(ByteBuffer src) throws IOException {
if (closed.get() || outputShutdown.get()) {
throw new ClosedChannelException();
}
writeLock.lock();
try {
// 检查底层通道是否仍然打开
if (outputChannel != null && !outputChannel.isOpen()) {
outputShutdown.set(true);
throw new ClosedChannelException();
}
int totalWritten = 0;
while (src.hasRemaining()) {
// 如果写缓冲区有空间,先填充
if (writeBuffer.hasRemaining()) {
int bytesToCopy = Math.min(writeBuffer.remaining(), src.remaining());
int oldlimit= src.limit();
src.limit(src.position()+bytesToCopy);
writeBuffer.put(src);
src.limit(oldlimit);
totalWritten += bytesToCopy;
}
// 如果写缓冲区满了或者源数据还很多,刷新缓冲区
if (!writeBuffer.hasRemaining() ) {
try {
flushInternal();
} catch (IOException e) {
outputShutdown.set(true);
throw e;
}
}
}
return totalWritten;
} finally {
writeLock.unlock();
}
}
@Override
public long write(ByteBuffer[] srcs) throws IOException {
return write(srcs, 0, srcs.length);
}
@Override
public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
if (closed.get() || outputShutdown.get()) {
throw new ClosedChannelException();
}
long totalWritten = 0;
for (int i = offset; i < offset + length; i++) {
ByteBuffer src = srcs[i];
if (src == null) {
throw new NullPointerException("Source buffer is null");
}
int bytesWritten = write(src);
totalWritten += bytesWritten;
}
return totalWritten;
}
/**
* 安全的刷新方法
*/
public void flush() throws IOException {
if (closed.get()) {
throw new ClosedChannelException();
}
if (outputChannel == null || outputShutdown.get()) {
return;
}
writeLock.lock();
try {
flushInternal();
} catch (IOException e) {
outputShutdown.set(true);
throw e;
} finally {
writeLock.unlock();
}
}
/**
* 内部刷新方法,假设已经持有writeLock
*/
private void flushInternal() throws IOException {
if (writeBuffer.position() > 0) {
writeBuffer.flip();
try {
while (writeBuffer.hasRemaining()) {
int written = outputChannel.write(writeBuffer);
// System.out.println("发送"+written);
if (written == 0) {
// 可能遇到阻塞或关闭
if (!outputChannel.isOpen()) {
outputShutdown.set(true);
throw new ClosedChannelException();
}
// 给其他操作机会
Thread.yield();
}
}
} finally {
// 无论发生什么,确保写缓冲区处于可写状态
writeBuffer.clear();
}
}
}
/**
* 安全的关闭方法
*/
@Override
public void close() throws IOException {
if (!closed.compareAndSet(false, true)) {
return; // 已经关闭
}
IOException exception = null;
// 先刷新输出缓冲区
if (outputChannel != null && !outputShutdown.get()) {
writeLock.lock();
try {
if (writeBuffer.position() > 0) {
try {
flushInternal();
} catch (IOException e) {
exception = e;
}
}
} finally {
writeLock.unlock();
}
}
// 关闭底层通道
try {
if (inputChannel != null) {
inputChannel.close();
}
} catch (IOException e) {
if (exception == null) {
exception = e;
} else {
exception.addSuppressed(e);
}
}
try {
if (outputChannel != null) {
outputChannel.close();
}
} catch (IOException e) {
if (exception == null) {
exception = e;
} else {
exception.addSuppressed(e);
}
}
// 清理缓冲区状态
readLock.lock();
try {
readBuffer.clear();
readBuffer.limit(0); // 标记为已清空
} finally {
readLock.unlock();
}
writeLock.lock();
try {
writeBuffer.clear();
} finally {
writeLock.unlock();
}
// 设置关闭状态
inputShutdown.set(true);
outputShutdown.set(true);
if (exception != null) {
throw exception;
}
}
/**
* 优雅关闭 - 只关闭输入或输出
*/
public void shutdownInput() throws IOException {
inputShutdown.set(true);
readLock.lock();
try {
readBuffer.clear();
readBuffer.limit(0);
} finally {
readLock.unlock();
}
if (inputChannel instanceof SocketChannel) {
((SocketChannel) inputChannel).shutdownInput();
}
}
public void shutdownOutput() throws IOException {
outputShutdown.set(true);
writeLock.lock();
try {
if (writeBuffer.position() > 0) {
flushInternal();
}
} finally {
writeLock.unlock();
}
if (outputChannel instanceof SocketChannel) {
((SocketChannel) outputChannel).shutdownOutput();
}
}
@Override
public boolean isOpen() {
return !closed.get() &&
(inputChannel == null || inputChannel.isOpen()) &&
(outputChannel == null || outputChannel.isOpen());
}
/**
* 检查是否还有可读数据(包括缓冲区中的)
*/
public boolean hasRemaining() throws IOException {
if (closed.get() || inputShutdown.get()) {
return false;
}
readLock.lock();
try {
return readBuffer.hasRemaining() ||
(inputChannel != null && inputChannel.isOpen());
} finally {
readLock.unlock();
}
}
/**
* 获取缓冲区状态信息(用于调试)
*/
public String getBufferState() {
readLock.lock();
writeLock.lock();
try {
return String.format(
"ReadBuffer[pos=%d, lim=%d, cap=%d], WriteBuffer[pos=%d, lim=%d, cap=%d], " +
"closed=%b, inputShutdown=%b, outputShutdown=%b",
readBuffer.position(), readBuffer.limit(), readBuffer.capacity(),
writeBuffer.position(), writeBuffer.limit(), writeBuffer.capacity(),
closed.get(), inputShutdown.get(), outputShutdown.get()
);
} finally {
writeLock.unlock();
readLock.unlock();
}
}
// 其他方法保持不变...
public int available() throws IOException {
if (closed.get() || inputShutdown.get()) {
return 0;
}
readLock.lock();
try {
return readBuffer.remaining();
} finally {
readLock.unlock();
}
}
public long skip(long n) throws IOException {
// 实现保持不变...
return 0;
}
}