netty学习

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写会数据