package com.net.tcp;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
*
* TCP通信數據緩存(粘包/半包處理)
*
*/
public class DataCache {
/**數據包*/
private List<DataPack> packs;
private ByteBuffer cache;
public DataCache(int capacity){
packs = new ArrayList<DataPack>();
cache = ByteBuffer.allocate(capacity);
}
/**
* 讀取字節流
* @param channel
* @return
* @throws Exception
*/
public int read(SocketChannel channel) throws Exception{
int reads = 0;
DataPack pack = null;
pack = lastUnComplete(true);
reads += readHead(channel, pack);
if(pack.getHead().getLen() > 0){
reads += readContent(channel, pack);
}
return reads;
}
/**
* 將所有包發送
* @param channel
* @return
* @throws Exception
*/
public boolean write(SocketChannel channel) throws Exception{
DataPack pack = null;
boolean sign = true;
Iterator<DataPack> it = packs.iterator();
while(it.hasNext() && sign){
pack = it.next();
channel.write(pack.getHead().getContent());
if(!pack.getHead().getContent().hasRemaining()){
ByteBuffer buffer = pack.getContent().current(false);
while(buffer != null){
channel.write(buffer);
if(buffer.hasRemaining()){
sign = false;
break;
}
buffer = pack.getContent().next(false);
}
}
}
return sign;
}
/**
* 返回隊頭,被移除
* @return
*/
public DataPack poll(){
if(packs.size() > 0){
DataPack pack = packs.get(0);
if(pack.isComplete(true)){
packs.remove(0);
return pack;
}
}
return null;
}
public void push(DataPack pack){
this.packs.add(pack);
}
/**
* 讀取包頭
* @param head
* @param channel
* @return
* @throws Exception
*/
private int readHead(SocketChannel channel, DataPack pack) throws Exception{
int reads = 0;
DataHead head = pack.getHead();
if(head.getLen() == 0){
reads = channel.read(head.getContent());
if(pack.getHead().isComplete()){
pack.getHead().init();
}
}
return reads;
}
/**
* 讀取內容
* @param channel
* @param pack
* @return
* @throws Exception
*/
private int readContent(SocketChannel channel, DataPack pack) throws Exception{
DataContent content = pack.getContent();
int reads = 0;
boolean sign = false;
while(!pack.isComplete(false)){
reads += channel.read(cache);
sign = cache.hasRemaining();
cache.flip();
content.put(cache);
cache.clear();
if(sign)
break;
}
if(pack.isComplete(false)){
pack.filp();
}
return reads;
}
/**
* 返回最後一個包
* @param create 傳true當最後一個包爲完整包時,創建一個新包
* @return
*/
public DataPack lastUnComplete(boolean create){
DataPack pack = null;
if(packs.size() > 0){
pack = packs.get(packs.size() - 1);
if(pack.isComplete(false) && create){
pack = new DataPack();
packs.add(pack);
}
}else{
pack = new DataPack();
packs.add(pack);
}
return pack;
}
}