服務端和客戶端的共用程式碼
【ConnectionInfo.java】
@Getter
@Setter
public class ConnectionInfo
{
private StringBuffer readBuffer = new StringBuffer();
private AtomicInteger readBufferIndex = new AtomicInteger(0);
private AtomicInteger blockCounter = new AtomicInteger(0);
}
【ConnectionInfos.java】
public class ConnectionInfos
{
private static ConcurrentHashMap<Channel, ConnectionInfo> connections = new ConcurrentHashMap<>();
public static ConnectionInfo put(Channel channel, ConnectionInfo connectionInfo) {
return connections.put(channel, connectionInfo);
}
public static ConnectionInfo get(Channel channel) {
return connections.get(channel);
}
public static ConnectionInfo remove(Channel channel) {
return connections.remove(channel);
}
}
【Constants.java】
public class Constants
{
public static final String spliterator = "----------------------end-----------------------";
}
服務端
pipeline
// out handler
socketChannel.pipeline().addLast(new StringEncoder());
// in handler
socketChannel.pipeline().addLast(new StringDecoder());
socketChannel.pipeline().addLast(new MyServerChannelInBoundHandler1());
socketChannel.pipeline().addLast(new MyServerChannelInBoundHandler2());
【MyServerChannelInBoundHandler1.java】
@Slf4j
public class MyServerChannelInBoundHandler1 extends SimpleChannelInboundHandler<String>
{
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
log.info("MyServerChannelInBoundHandler1.channelActive[" + ctx.channel().remoteAddress() + "]: ");
ctx.writeAndFlush("MyServerChannelInBoundHandler1: I'm server, thanks for connected!\r\n");
ConnectionInfos.put(ctx.channel(), new ConnectionInfo()); // 連線建立的時候放入一個連線物件
super.channelActive(ctx);
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
log.info("MyServerChannelInBoundHandler1.channelRead0[" + ctx.channel().remoteAddress() + "]:" + msg);
ConnectionInfo connectionInfo = ConnectionInfos.get(ctx.channel());
StringBuffer stringBuffer = connectionInfo.getReadBuffer();
stringBuffer.append(msg);
AtomicReference<String> targetHolder = new AtomicReference<>();
while(true){
// 每讀取到新資料就判斷一下是否有完成的資料到達
if( getTargetData(stringBuffer, true, targetHolder, connectionInfo.getReadBufferIndex()) ){
ctx.fireChannelRead(targetHolder.get()); // 讀取到完整大塊資料之後傳到下一個handler
targetHolder.set(null);
continue;
} else {
break;
}
}
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
log.info("MyServerChannelInBoundHandler1.channelInactive[" + ctx.channel().remoteAddress() + "]: ");
ConnectionInfos.remove(ctx.channel());
super.channelInactive(ctx);
}
// 根據分隔符讀取完整資料塊
private static boolean getTargetData(StringBuffer stringBuffer,
boolean modified,
AtomicReference<String> targetHolder,
AtomicInteger indexHolder)
{
int spliteratorIndex = stringBuffer.indexOf(Constants.spliterator, indexHolder.get());
if( spliteratorIndex<0 ){
indexHolder.set(Math.min(0, stringBuffer.length() - Constants.spliterator.length() - 2));
return false;
}
String targetData = stringBuffer.substring(0, spliteratorIndex);
if( modified ){
stringBuffer.delete(0, spliteratorIndex + Constants.spliterator.length() + 2);
indexHolder.set(0);
} else {
indexHolder.set(spliteratorIndex);
}
if( targetHolder!=null ){
targetHolder.set(targetData);
}
return true;
}
}
【MyServerChannelInBoundHandler2.java】
@Slf4j
public class MyServerChannelInBoundHandler2 extends SimpleChannelInboundHandler<String>
{
// 引數【msg】就是從上一個handler傳過來的完整的大塊資料
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
ConnectionInfo connectionInfo = ConnectionInfos.get(ctx.channel());
AtomicInteger blockCounter = connectionInfo.getBlockCounter();
blockCounter.getAndIncrement();
log.info("MyServerChannelInBoundHandler2.channelRead0[" + ctx.channel().remoteAddress() + "]:" + msg);
ctx.writeAndFlush(String.format("received [%d] blocks\r\n", blockCounter.get()));
}
}
客戶端
【MyClientInBoundHandler.java】
@Slf4j
public class MyClientInBoundHandler extends ChannelInboundHandlerAdapter
{
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
log.info("channelActive[" + ctx.channel().remoteAddress() + "]");
ctx.write("Hello, Server, I'm client 1!\r\n");
ctx.write(Constants.spliterator+"\r\n"); // 傳送每1個大塊分隔符
ctx.write("Hello, Server, I'm client 2!\r\n");
ctx.write(Constants.spliterator+"\r\n"); // 傳送每2個大塊分隔符
ctx.flush();
for( int i=0; i<100; i++ ){
ctx.writeAndFlush(String.format("[%010d]\r\n", i));
Thread.sleep(1L);
}
ctx.writeAndFlush(Constants.spliterator+"\r\n"); // 傳送每3個大塊分隔符
for( int i=0; i<100; i++ ){
ctx.writeAndFlush(String.format("[%010d]\r\n", i));
Thread.sleep(1L);
}
ctx.writeAndFlush(Constants.spliterator+"\r\n"); // 傳送每4個大塊分隔符
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
log.info("channelReadComplete[" + ctx.channel().remoteAddress() + "]: " );
super.channelReadComplete(ctx);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
log.info("channelRead[" + ctx.channel().remoteAddress() + "]: " + msg);
super.channelRead(ctx, msg);
}
}