1. Netty 能做什么
1. http服务器 类 Tomcat ,但是没有实现web规范
2. socket 开发 rpc通信
3. 长链接的开发
2. netty的http程序示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public class TestServer {
public static void main(String[] args) throws Exception{
//工作线程 EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup();
try { //服务启动器 ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup,workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new TestServerInitializer());
//绑定端口 ChannelFuture sync = bootstrap.bind(8899).sync();
sync.channel().closeFuture().sync();
} finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); }
}
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class TestServerInitializer extends ChannelInitializer<SocketChannel> {
@Override protected void initChannel(SocketChannel ch) throws Exception {
//管道可以拥有很多个handler,类似于拦截器 ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("httpServerCodec",new HttpServerCodec());
//自定义处理器
pipeline.addLast("testHttpServerHandler",new TestHttpServerHandler());
}
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class TestHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {
//类似于 msgReceived 方法 , //接收消息,返回响应 @Override protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
if (msg instanceof HttpRequest) { //构造一个响应内容 ByteBuf content = Unpooled.copiedBuffer("hello", CharsetUtil.UTF_8);
//构造响应体 FullHttpResponse response = new DefaultFullHttpResponse( HttpVersion.HTTP_1_1, HttpResponseStatus.OK,content );
response.headers().add(HttpHeaderNames.CONTENT_TYPE,"text/plain"); response.headers().add(HttpHeaderNames.CONTENT_LENGTH,content.readableBytes());
//回写response ctx.writeAndFlush(response);
} } }
|
使用:
浏览器 localhost:8899
curl localhost:8899
3. netty实现socket编程示例
3.1 SocketServer的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| public class TestSocketServer {
public static void main(String[] args) throws Exception {
NioEventLoopGroup bossGroup = new NioEventLoopGroup(); NioEventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup,workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new TestSocketServerInitializer());
ChannelFuture sync = bootstrap.bind(8899).sync();
sync.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } }
public class TestSocketServerInitializer extends ChannelInitializer<SocketChannel> {
@Override protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new LengthFieldBasedFrameDecoder( Integer.MAX_VALUE,0,4,0,4));
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new TestSocketServerHandler());
} }
@Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
SocketAddress socketAddress = ctx.channel().remoteAddress();
System.out.println(socketAddress + " : " + msg );
ctx.writeAndFlush("write from server : " + UUID.randomUUID());
}
|
3.2 SocketClient的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| public class MySocketClient {
public static void main(String[] args) throws Exception {
NioEventLoopGroup loop = new NioEventLoopGroup();
try { Bootstrap bootstrap = new Bootstrap();
bootstrap.group(loop) .channel(NioSocketChannel.class) .handler(new MySocketClientInitializer());
ChannelFuture future = bootstrap.connect("localhost", 8899).sync();
future.channel().closeFuture().sync();
} finally { loop.shutdownGracefully(); }
}
}
public class MySocketClientInitializer extends ChannelInitializer<SocketChannel> {
@Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new LengthFieldBasedFrameDecoder( Integer.MAX_VALUE,0,4,0,4));
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new MySocketClientHandler());
} }
class MySocketClientHandler extends SimpleChannelInboundHandler<String> {
@Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { System.out.println(ctx.channel().remoteAddress() + " : " + msg);
ctx.writeAndFlush("from client : " + LocalDateTime.now()); }
@Override public void channelActive(ChannelHandlerContext ctx) throws Exception { super.channelActive(ctx);
ctx.writeAndFlush("sss"); }
@Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { // super.exceptionCaught(ctx, cause); cause.printStackTrace();
ctx.close(); } }
|
分别启动服务端和客户端就可以在命令行看到输出
4. netty编程流程总结
在Netty中,几乎所有的代码编写流程都遵循以下流程
服务端:
1. 构建 ServerBootstrap
创建工作线程 NioEventLoopGroup
指定channel NioServerSocketChannel
指定handler
2. 构建ChannelInitializer
获取ChannelPipeline 添加netty处理器
添加自定义处理器
3. 编写自定义处理器
继承SimpleChannelInboundHandler 接收参数
然后通过ChannelHandlerContext写会数据
socket客户端:
1. 构建 Bootstrap
创建工作线程 NioEventLoopGroup
指定channel NioSocketChannel
指定handler
2. 构建ChannelInitializer
获取ChannelPipeline 添加netty处理器
添加自定义处理器
3. 编写自定义处理器
继承SimpleChannelInboundHandler 接收参数
然后通过ChannelHandlerContext写会数据