目录
1.引导类类图概览
引导类包内比较简单,大致就4部分:客户端/无连接引导类以及配置、服务端引导类及其配置。类图如下:
2.使用
2.1服务端引导类
public class EchoServer {
private final int port;
public EchoServer(int port) {
this.port = port;
}
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println(
"Usage: " + EchoServer.class.getSimpleName() +
" <port>");
return;
}
int port = Integer.parseInt(args[0]);
new EchoServer(port).start();
}
public void start() throws Exception {
NioEventLoopGroup group = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(group)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast(
new EchoServerHandler());
}
});
ChannelFuture f = b.bind().sync();
System.out.println(EchoServer.class.getName() + " started and listen on " + f.channel().localAddress());
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
}
@ChannelHandler.Sharable
public class EchoServerHandler extends
ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx,
Object msg) {
ByteBuf in = (ByteBuf) msg;
System.out.println("Server received: " + in.toString(CharsetUtil.UTF_8));
ctx.write(in);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
.addListener(ChannelFutureListener.CLOSE);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
2.2客户端/无连接引导类
public class EchoClient {
private final String host;
private final int port;
public EchoClient(String host, int port) {
this.host = host;
this.port = port;
}
public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.remoteAddress(new InetSocketAddress(host, port))
.handler(new ChannelInitializer<SocketChannel>() { //5
@Override
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast(
new EchoClientHandler());
}
});
ChannelFuture f = b.connect().sync();
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws Exception {
if (args.length != 2) {
System.err.println(
"Usage: " + EchoClient.class.getSimpleName() +
" <host> <port>");
return;
}
final String host = args[0];
final int port = Integer.parseInt(args[1]);
new EchoClient(host, port).start();
}
}
@ChannelHandler.Sharable
public class EchoClientHandler extends
SimpleChannelInboundHandler<ByteBuf> {
@Override
public void channelActive(ChannelHandlerContext ctx) {
ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!",
CharsetUtil.UTF_8));
}
@Override
public void channelRead0(ChannelHandlerContext ctx,
ByteBuf in) {
System.out.println("Client received: " + in.toString(CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
2.3.运行
项目使用Maven构建,内含2个子模块,echoserver和echoclient。目录结构如下:
启动netty服务端。打开一个终端,到echoserver目录下执行
mvn exec:java -Dexec.mainClass="com.mclarenp.netty.demo.EchoServer" -Dexec.args="8081"
启动netty客户端。打开另外一个终端,到echoclient目录下执行
mvn exec:java -Dexec.mainClass="com.mclarenp.netty.demo.EchoClient" -Dexec.args="localhost 8081"
看到netty客户端输出:
看到netty服务端输出:
3.过程分析
3.1 引导客户端/无连接过程
1)创建Bootstrap来和服务端通道连接
2)给Bootstrap实例指定EventLoopGroup
3)给Bootstrap实例指定Channel
4)给Bootstrap实例指定要连接的服务端IP、端口
5)给Boostrap实例指定Handler。new一个Channel实现类ChannelInitializer,并往ChannelPipeline添加自定义Handler
6)阻塞直到连接完成
7)等待服务器端关闭socket
8)关闭事件循环组
3.2 引导服务端过程
1)创建ServerBootstrap来和监听客户端连接
2)给ServerBootstrap实例指定EventLoopGroup
3)给ServerBootstrap实例指定Channel
4)给ServerBootstrap实例指定要绑定的端口
5)给ServerBoostrap实例指定Handler。new一个Channel实现类ChannelInitializer,并往ChannelPipeline添加自定义Handler
6)阻塞直到服务端启动
7)等待服务器端关闭socket
8)关闭事件循环组