Netty中的netty channelgroupRead和messageReceived的区别

Netty入门二:开发第一个Netty应用程序
既然是入门,那我们就在这里写一个简单的Demo,客户端发送一个字符串到服务器端,服务器端接收字符串后再发送回客户端。
2.1、配置开发环境
2.去官网下载jar包
(或者通过pom构建)
2.2、认识下Netty的Client和Server
一个Netty应用模型,如下图所示,但需要明白一点的是,我们写的Server会自动处理多客户端请求,理论上讲,处理并发的能力决定于我们的配置及JDK的极限。
vcXUo6y+zcrHus3Jvb2owaLBy8G0vdOjrMTjz/LJvbTzurDBy9K7yfmjrL7NtPqx7c/yyb23osvNwcvK/b7do6zE47XEurDJ+b6tuf3JvbXEt7TJ5NDOs8nBy7vYyfmjrNXiuPa72Mn5vs3Kx7f+zvHG97XEz+zTpsr9vt2ho8jnufvE47/J0tTA67+qo6y+zbT6se22z7+qwcvBtL3To6y1sci7xOPSsr/J0tTU2bvYwLSho9K7tM6/ydLUuvO6w7bgyMvP8sm9tPO6sKOsy/vDx7XEurDJ+dKy0ru2qLvhtcO1vcm9tcS72NOmoaMKCjxzdHJvbmc+Mi4zINC00ru49k5ldHR5IFNlcnZlcjwvc3Ryb25nPgogICAgINK7uPZOZXR0eVNlcnZlcrPM0PLW99Kq08nBvbK/t9bX6bPJo7oKCgpCb290c1RyYXBwaW5nOsXk1sO3/s7xxve2y7v5sb7Qxc+iU2VydmVySGFuZGxlcjrV5tX9tcTStc7xwt+8rbSmwO0KPHN0cm9uZz4yLjMuMSBCb290c1RyYXBwaW5ntcS5/bPMOjwvc3Ryb25nPgo8cHJlIGNsYXNzPQ=="brush:">package NettyDemo.echo.
import io.netty.bootstrap.ServerB
import io.netty.channel.ChannelF
import io.netty.channel.ChannelI
import io.netty.channel.EventLoopG
import io.netty.channel.nio.NioEventLoopG
import io.netty.channel.socket.SocketC
import io.netty.channel.socket.nio.NioServerSocketC
import java.net.InetSocketA
import NettyDemo.echo.handler.EchoServerH
public class EchoServer {
private static final int port = 8080;
public void start() throws InterruptedException {
ServerBootstrap b = new ServerBootstrap();// 引导辅助程序
EventLoopGroup group = new NioEventLoopGroup();// 通过nio方式来接收连接和处理连接
b.group(group);
b.channel(NioServerSocketChannel.class);// 设置nio类型的channel
b.localAddress(new InetSocketAddress(port));// 设置监听端口
b.childHandler(new ChannelInitializer() {//有连接到达时会创建一个channel
protected void initChannel(SocketChannel ch) throws Exception {
// pipeline管理channel中的Handler,在channel队列中添加一个handler来处理业务
ch.pipeline().addLast("myHandler", new EchoServerHandler());
ChannelFuture f = b.bind().sync();// 配置完成,开始绑定server,通过调用sync同步方法阻塞直到绑定成功
System.out.println(EchoServer.class.getName() + " started and listen on " + f.channel().localAddress());
f.channel().closeFuture().sync();// 应用程序会一直等待,直到channel关闭
} catch (Exception e) {
e.printStackTrace();
} finally {
group.shutdownGracefully().sync();//关闭EventLoopGroup,释放掉所有资源包括创建的线程
public static void main(String[] args) {
new EchoServer().start();
} catch (InterruptedException e) {
e.printStackTrace();
1. 创建一个ServerBootstrap实例
2. 创建一个EventLoopGroup来处理各种事件,如处理链接请求,发送接收数据等。
3. 定义本地InetSocketAddress( port)好让Server绑定
4. 创建childHandler来处理每一个链接请求
5. 所有准备好之后调用ServerBootstrap.bind()方法绑定Server
2.3.2 业务逻辑ServerHandler:
要想处理接收到的数据,我们必须继承ChannelInboundHandlerAdapter接口,重写里面的MessageReceive方法,每当有数据到达,此方法就会被调用(一般是Byte类型数组),我们就在这里写我们的业务逻辑:
package NettyDemo.echo.
import io.netty.buffer.U
import io.netty.channel.ChannelFutureL
import io.netty.channel.ChannelHandlerC
import io.netty.channel.ChannelInboundHandlerA
import io.netty.channel.ChannelHandler.S
* Sharable表示此对象在channel间共享
* handler类是我们的具体业务类
@Sharable//注解@Sharable可以让它在channels间共享
public class EchoServerHandler extends ChannelInboundHandlerAdapter{
public void channelRead(ChannelHandlerContext ctx, Object msg) {
System.out.println("server received data :" + msg);
ctx.write(msg);//写回数据,
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER) //flush掉所有写回的数据
.addListener(ChannelFutureListener.CLOSE); //当flush完成后关闭channel
public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause) {
cause.printStackTrace();//捕捉异常信息
ctx.close();//出现异常时关闭channel
2.3.3关于异常处理:
我们在上面程序中也重写了exceptionCaught方法,这里就是对当异常出现时的处理。
2.4 写一个Netty Client
一般一个简单的Client会扮演如下角色:
连接到Server向Server写数据等待Server返回数据关闭连接
4.4.1 BootsTrapping的过程:
和Server端类似,只不过Client端要同时指定连接主机的IP和Port。
package NettyDemo.echo.
import io.netty.bootstrap.B
import io.netty.channel.ChannelF
import io.netty.channel.ChannelFutureL
import io.netty.channel.ChannelI
import io.netty.channel.EventLoopG
import io.netty.channel.nio.NioEventLoopG
import io.netty.channel.socket.SocketC
import io.netty.channel.socket.nio.NioSocketC
import java.net.InetSocketA
import NettyDemo.echo.handler.EchoClientH
public class EchoClient {
private final S
public EchoClient(String host, int port) {
this.host =
this.port =
public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group);
b.channel(NioSocketChannel.class);
b.remoteAddress(new InetSocketAddress(host, port));
b.handler(new ChannelInitializer() {
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new EchoClientHandler());
ChannelFuture f = b.connect().sync();
f.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
if(future.isSuccess()){
System.out.println("client connected");
System.out.println("server attemp failed");
future.cause().printStackTrace();
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
public static void main(String[] args) throws Exception {
new EchoClient("127.0.0.1", 3331).start();
1. 创建一个ServerBootstrap实例
2. 创建一个EventLoopGroup来处理各种事件,如处理链接请求,发送接收数据等。
3. 定义一个远程InetSocketAddress好让客户端连接
4. 当连接完成之后,Handler会被执行一次
5. 所有准备好之后调用ServerBootstrap.connect()方法连接Server
4.4.2 业务逻辑ClientHandler:
我们同样继承一个SimpleChannelInboundHandler来实现我们的Client,我们需要重写其中的三个方法:
package NettyDemo.echo.
import io.netty.buffer.ByteB
import io.netty.buffer.ByteBufU
import io.netty.buffer.U
import io.netty.channel.ChannelHandlerC
import io.netty.channel.SimpleChannelInboundH
import io.netty.channel.ChannelHandler.S
import io.netty.util.CharsetU
public class EchoClientHandler extends SimpleChannelInboundHandler {
*此方法会在连接到服务器后被调用
public void channelActive(ChannelHandlerContext ctx) {
ctx.write(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8));
*此方法会在接收到服务器数据后调用
public void channelRead0(ChannelHandlerContext ctx, ByteBuf in) {
System.out.println("Client received: " + ByteBufUtil.hexDump(in.readBytes(in.readableBytes())));
*捕捉到异常
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
其中需要注意的是channelRead0()方法,此方法接收到的可能是一些数据片段,比如服务器发送了5个字节数据,Client端不能保证一次全部收到,比如第一次收到3个字节,第二次收到2个字节。我们可能还会关心收到这些片段的顺序是否可发送顺序一致,这要看具体是什么协议,比如基于TCP协议的字节流是能保证顺序的。
还有一点,在Client端我们的业务Handler继承的是SimpleChannelInboundHandler,而在服务器端继承的是ChannelInboundHandlerAdapter,那么这两个有什么区别呢?最主要的区别就是SimpleChannelInboundHandler在接收到数据后会自动release掉数据占用的Bytebuffer资源(自动调用Bytebuffer.release())。而为何服务器端不能用呢,因为我们想让服务器把客户端请求的数据发送回去,而服务器端有可能在channelRead方法返回前还没有写完数据,因此不能让它自动release。
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'Netty实现网络通信 -
- ITeye技术网站
原文同步至
是一个 Java NIO 客户端服务器框架,使用它可以快速简单地开发网络应用程序,比如服务器和客户端的协议。Netty 大大简化了网络程序的开发过程比如 TCP 和 UDP 的 socket 服务的开发。更多关于 Netty 的知识,可以参阅《Netty 4.x 用户指南》()
下面,就基于 Netty 快速实现一个聊天小程序。
Maven 3.2.x
Eclipse 4.x
让我们从 handler (处理器)的实现开始,handler 是由 Netty 生成用来处理 I/O 事件的。
SimpleChatServerHandler.java
public class SimpleChatServerHandler extends SimpleChannelInboundHandler&String& {
public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
Channel incoming = ctx.channel();
for (Channel channel : channels) {
channel.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 加入\n");
channels.add(ctx.channel());
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Channel incoming = ctx.channel();
for (Channel channel : channels) {
channel.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 离开\n");
channels.remove(ctx.channel());
protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception {
Channel incoming = ctx.channel();
for (Channel channel : channels) {
if (channel != incoming){
channel.writeAndFlush("[" + incoming.remoteAddress() + "]" + s + "\n");
channel.writeAndFlush("[you]" + s + "\n");
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel incoming = ctx.channel();
System.out.println("SimpleChatClient:"+incoming.remoteAddress()+"在线");
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Channel incoming = ctx.channel();
System.out.println("SimpleChatClient:"+incoming.remoteAddress()+"掉线");
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
Channel incoming = ctx.channel();
System.out.println("SimpleChatClient:"+incoming.remoteAddress()+"异常");
cause.printStackTrace();
ctx.close();
1.SimpleChatServerHandler 继承自 ,这个类实现了
接口,ChannelInboundHandler 提供了许多事件处理的接口方法,然后你可以覆盖这些方法。现在仅仅只需要继承 SimpleChannelInboundHandler 类而不是你自己去实现接口方法。
2.覆盖了 handlerAdded() 事件处理方法。每当从服务端收到新的客户端连接时,客户端的 Channel 存入 列表中,并通知列表中的其他客户端 Channel
3.覆盖了 handlerRemoved() 事件处理方法。每当从服务端收到客户端断开时,客户端的 Channel 移除 ChannelGroup 列表中,并通知列表中的其他客户端 Channel
4.覆盖了 channelRead0() 事件处理方法。每当从服务端读到客户端写入信息时,将信息转发给其他客户端的 Channel。其中如果你使用的是 Netty 5.x 版本时,需要把 channelRead0() 重命名为messageReceived()
5.覆盖了 channelActive() 事件处理方法。服务端监听到客户端活动
6.覆盖了 channelInactive() 事件处理方法。服务端监听到客户端不活动
7.exceptionCaught() 事件处理方法是当出现 Throwable 对象才会被调用,即当 Netty 由于 IO 错误或者处理器在处理事件时抛出的异常时。在大部分情况下,捕获的异常应该被记录下来并且把关联的 channel 给关闭掉。然而这个方法的处理方式会在遇到不同异常的情况下有不同的实现,比如你可能想在关闭连接之前发送一个错误码的响应消息。
SimpleChatServerInitializer.java
SimpleChatServerInitializer 用来增加多个的处理类到 ChannelPipeline 上,包括编码、解码、SimpleChatServerHandler 等。
public class SimpleChatServerInitializer extends
ChannelInitializer&SocketChannel& {
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(<span class="hljs-number" style="padding: 0 margin: 0 color: #, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new SimpleChatServerHandler());
System.out.println("SimpleChatClient:"+ch.remoteAddress() +"连接上");
SimpleChatServer.java
编写一个 main() 方法来启动服务端。
public class SimpleChatServer {
private int
public SimpleChatServer(int port) {
this.port =
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new SimpleChatServerInitializer())
.option(ChannelOption.SO_BACKLOG, <span class="hljs-number" style="padding: 0 margin: 0 color: #)
.childOption(ChannelOption.SO_KEEPALIVE, true);
System.out.println("SimpleChatServer 启动了");
ChannelFuture f = b.bind(port).sync();
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
System.out.println("SimpleChatServer 关闭了");
public static void main(String[] args) throws Exception {
if (args.length & 0) {
port = Integer.parseInt(args[0]);
port = <span class="hljs-number" style="padding: 0 margin: 0 color: #;
new SimpleChatServer(port).run();
1. 是用来处理I/O操作的多线程事件循环器,Netty 提供了许多不同的
的实现用来处理不同的传输。在这个例子中我们实现了一个服务端的应用,因此会有2个 NioEventLoopGroup 会被使用。第一个经常被叫做‘boss’,用来接收进来的连接。第二个经常被叫做‘worker’,用来处理已经被接收的连接,一旦‘boss’接收到连接,就会把连接信息注册到‘worker’上。如何知道多少个线程已经被使用,如何映射到已经创建的上都需要依赖于 EventLoopGroup 的实现,并且可以通过构造函数来配置他们的关系。
2. 是一个启动 NIO 服务的辅助启动类。你可以在这个服务中直接使用 Channel,但是这会是一个复杂的处理过程,在很多情况下你并不需要这样做。
3.这里我们指定使用
类来举例说明一个新的 Channel 如何接收进来的连接。
4.这里的事件处理类经常会被用来处理一个最近的已经接收的 Channel。SimpleChatServerInitializer 继承自 是一个特殊的处理类,他的目的是帮助使用者配置一个新的 Channel。也许你想通过增加一些处理类比如 SimpleChatServerHandler 来配置一个新的 Channel 或者其对应的 来实现你的网络程序。当你的程序变的复杂时,可能你会增加更多的处理类到 pipline 上,然后提取这些匿名类到最顶层的类上。
5.你可以设置这里指定的 Channel 实现的配置参数。我们正在写一个TCP/IP 的服务端,因此我们被允许设置 socket 的参数选项比如tcpNoDelay 和 keepAlive。请参考
实现的接口文档以此可以对ChannelOption 的有一个大概的认识。
6.option() 是提供给 用来接收进来的连接。childOption() 是提供给由父管道 接收到的连接,在这个例子中也是 NioServerSocketChannel。
7.我们继续,剩下的就是绑定端口然后启动服务。这里我们在机器上绑定了机器所有网卡上的 8080 端口。当然现在你可以多次调用 bind() 方法(基于不同绑定地址)。
恭喜!你已经完成了基于 Netty 聊天服务端程序。
SimpleChatClientHandler.java
客户端的处理类比较简单,只需要将读到的信息打印出来即可
public class SimpleChatClientHandler extends
SimpleChannelInboundHandler&String& {
protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception {
System.out.println(s);
SimpleChatClientInitializer.java
与服务端类似
public class SimpleChatClientInitializer extends ChannelInitializer&SocketChannel& {
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(<span class="hljs-number" style="padding: 0 margin: 0 color: #, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new SimpleChatClientHandler());
SimpleChatClient.java
编写一个 main() 方法来启动客户端。
public class SimpleChatClient {
public static void main(String[] args) throws Exception{
new SimpleChatClient("localhost", <span class="hljs-number" style="padding: 0 margin: 0 color: #).run();
private final S
private final int
public SimpleChatClient(String host, int port){
this.host =
this.port =
public void run() throws Exception{
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap
= new Bootstrap()
.group(group)
.channel(NioSocketChannel.class)
.handler(new SimpleChatClientInitializer());
Channel channel = bootstrap.connect(host, port).sync().channel();
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while(true){
channel.writeAndFlush(in.readLine() + "\r\n");
} catch (Exception e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
先运行 SimpleChatServer,再可以运行多个 SimpleChatClient,控制台输入文本继续测试
liuzhiqiang
浏览: 8276 次
来自: 北京深入浅出Netty_图文_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
深入浅出Netty
上传于|0|0|文档简介
阅读已结束,如果下载本文需要使用2下载券
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩29页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢}

我要回帖

更多关于 netty channelfuture 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信