Netty简介
netty是Java著名的nio库之一,以前是JBoss的项目,现在独立出来成为
io.netty。经测试Netty的性能比node.js更胜一筹,其内存和CPU占用率比其他的网络库低很多。Netty 4.x在3.x的基础上修改了一些接口,5.x版本在保持接口不变的情况下对内部架构作了一些优化。目前最新版是4.1和5.0同步更新。
为了学习nio,准备用netty实现一个端对端的收发packet的简单程序,服务器端与客户端之间互传任意长度的packet。
Packet的设计相当简单,直接用[len][content]构成,len为固定的2byte 16位,后面的content为长度为len的二进制流,其读写代码也很简单,直接用InputStream和OutputStream来处理输入和输出,可读写Socket,处理蓝牙数据流或tcp数据流:
public class Packet {
public static final int MAX_LEN = 0xffff;
public static class PacketInputStream {
private final InputStream stream;
private final byte[] twoBytes = new byte[2];
public PacketInputStream(InputStream s) {
stream = s;
}
public ByteBuffer readPacket() throws IOException {
readBytes(twoBytes);
int len = ((twoBytes[0] & 0xff) << 8) | twoBytes[1];
byte[] buffer = new byte[len];
return ByteBuffer.wrap(readBytes(buffer));
}
public byte[] readBytes(byte[] buffer) throws IOException {
int bytes = 0;
while (bytes < buffer.length) {
int n = stream.read(buffer, bytes, buffer.length - bytes);
if (n < 0) {
throw new IOException();
}
bytes += n;
}
return buffer;
}
}
public static class PacketOutputStream {
private OutputStream stream;
public static ByteBuffer createPacket(int len) {
return ByteBuffer.allocate(len).putShort((short) len);
}
public PacketOutputStream(OutputStream out) {
stream = out;
}
public void writePacket(ByteBuffer buffer) throws IOException {
writeByte(buffer.array());
}
public void writeByte(byte[] buffer) throws IOException{
stream.write(buffer);
stream.flush(); //确保整个包被一次性发出去
}
}
}
1. 根据EchoServer改的简单版
没耐心仔细读文档,先把example过一遍。
package com.company.nettytest;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
* Created by fripside on 8/1/15.
* http://my.oschina.net/flashsword/blog/162936
*/
public class NettyClient {
public static void main(String[] args) {
EventLoopGroup group = new NioEventLoopGroup(1);
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline p = socketChannel.pipeline();
p.addLast(new ClientHandler());
}
});
ChannelFuture f = b.connect("127.0.0.1", 8888).sync();
f.channel().closeFuture().sync();
} catch (Exception e) {
} finally {
group.shutdownGracefully();
}
}
public void sendRandomPck() {
}
}
class ReceivePackets {
private BlockingQueue<Packet> packets = new ArrayBlockingQueue<>(100);
}
class ClientHandler extends ChannelHandlerAdapter {
private final ByteBuf firstMessage;
private int times = 10;
private final byte[] twoBytes = new byte[2];
public ClientHandler() {
firstMessage = Unpooled.buffer(256);
firstMessage.writeShort(254);
for (int i = 2; i < firstMessage.capacity(); ++i) {
firstMessage.writeByte((byte) i);
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(firstMessage);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (times < 0) {
ctx.close();
}
ByteBuf buf = (ByteBuf) msg;
buf.readBytes(twoBytes);
System.out.println("b1:" + twoBytes[0] + " b2:" + twoBytes[1]);
int len = ((twoBytes[0] << 8) & 0xff00) | (twoBytes[1] & 0xff);
System.out.println("LEN: " + len + " Available:" + buf.readableBytes());
byte[] all = new byte[len];
buf.readBytes(all, 0, len);
ctx.write(msg);
System.out.println("Receive: " + times + " " + all);
--times;
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
package com.company.nettytest;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Created by fripside on 8/1/15.
*/
public class NettyServer {
static Logger LOG = Logger.getGlobal();
public static void main(String[] args) {
LOG.setLevel(Level.INFO);
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler())
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
LOG.info("client is connect....");
ChannelPipeline p = socketChannel.pipeline();
p.addLast(new ServerHandler());
}
});
LOG.info("server is start....");
ChannelFuture f = b.bind(8888).sync();
f.channel().closeFuture().sync();
} catch (Exception e) {
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
class ServerHandler extends ChannelHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ctx.write(msg);
System.out.println(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}