前言介绍:

    我们的NettyServer收到数据后,需要群发给当前链接到服务端的所有小伙伴。

    技术点:

    1、ChannelGroup 【io.netty.channel.group.DefaultChannelGroup】

欢迎加入:itstack | Netty The Sniper 5360692

环境需求:

    1、jdk1.7以上【jdk1.7以下只能部分支持netty】

    2、Netty-all-5.0【netty3.x 4.x 5每次的变化较大,接口类名也随着变化】

    3、telnet 测试【可以现在你的win7机器上测试这个命令,用于链接到服务端的测试命令】【本案例中已经很不好满足测试需求了】

    4、最好下载个网络调试助手,它能帮助你测试服务端、客户端

代码部分:

======================

TestNettyServerBaseDemo 

    src 

        com.itstack 

            ChildChannelHandler.java 

            MyChannelHandlerPool.java
            MyServerHanlder.java
NettyServer.java

======================

ChildChannelHandler.java

1. package.itstack;
2.  
3. import.netty.buffer.ByteBuf;
4. import.netty.buffer.Unpooled;
5. import.netty.channel.ChannelInitializer;
6. import.netty.channel.socket.SocketChannel;
7. import.netty.handler.codec.DelimiterBasedFrameDecoder;
8. import.netty.handler.codec.Delimiters;
9. import.netty.handler.codec.FixedLengthFrameDecoder;
10. import.netty.handler.codec.LineBasedFrameDecoder;
11. import.netty.handler.codec.string.StringDecoder;
12. import.netty.handler.codec.string.StringEncoder;
13.  
14. publicclassChildChannelHandlerextendsChannelInitializer<SocketChannel>{
15.  
16. @Override
17. protectedvoid(SocketChannel)throwsException{
18.  
19. System.out.println("报告");
20. System.out.println("信息:有一客户端链接到本服务端");
21. System.out.println("IP:"+.localAddress().getHostName());
22. System.out.println("Port:"+.localAddress().getPort());
23. System.out.println("报告完毕");
24.  
25. // 解码器
26. // 基于换行符号
27. .pipeline().addLast(newLineBasedFrameDecoder(1024));
28. 
29. // 基于指定字符串【换行符,这样功能等同于LineBasedFrameDecoder】
30. //		e.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, false, Delimiters.lineDelimiter()));
31. // 基于最大长度
32. //		e.pipeline().addLast(new FixedLengthFrameDecoder(4));
33. // 解码转String
34. .pipeline().addLast(newStringDecoder());
35.  
36. // 编码器 String
37. .pipeline().addLast(newStringEncoder());
38. 
39. // 在管道中添加我们自己的接收数据实现方法
40. .pipeline().addLast(newMyServerHanlder());
41.  
42. }
43.  
44. }

MyChannelHandlerPool.java

    1. package.itstack;
    2.  
    3. import.netty.channel.group.ChannelGroup;
    4. import.netty.channel.group.DefaultChannelGroup;
    5. import.netty.util.concurrent.GlobalEventExecutor;
    6.  
    7. /**
    8.  * 
    9.  * 这里讲ChannelGroup单独放到一个类里,并有多个客户端使用
    10.  * 同时ChannelGroup是static的
    11.  * 说明:这不是唯一的处理方式
    12.  *
    13.  */
    14. publicclassMyChannelHandlerPool{
    15.  
    16. publicstaticChannelGroup=newDefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    17. 
    18. }
     
    MyServerHanlder.java 
    
    1. package.itstack;
    2.  
    3. import.util.Date;
    4.  
    5. import.netty.buffer.ByteBuf;
    6. import.netty.buffer.Unpooled;
    7. import.netty.channel.ChannelHandlerAdapter;
    8. import.netty.channel.ChannelHandlerContext;
    9. import.netty.handler.codec.bytes.ByteArrayDecoder;
    10.  
    11. publicclassMyServerHanlderextendsChannelHandlerAdapter{
    12.  
    13. /*
    14. 	 * channelAction 
    15. 	 * 
    16. 	 * channel 通道
    17. 	 * action  活跃的
    18. 	 * 
    19. 	 * 当客户端主动链接服务端的链接后,这个通道就是活跃的了。也就是客户端与服务端建立了通信通道并且可以传输数据
    20. 	 * 
    21. 	 */
    22. publicvoid(ChannelHandlerContext)throwsException{
    23. 
    24. System.out.println(ctx.channel().localAddress().toString()+" channelActive");
    25. 
    26. //添加到channelGroup 通道组
    27. MyChannelHandlerPool.channelGroup.add(ctx.channel());
    28. 
    29. //通知您已经链接上客户端
    30. String="您已经开启与服务端链接"+" "+ctx.channel().id()+newDate()+" "+ctx.channel().localAddress();
    31. .writeAndFlush(str);
    32. 
    33. }
    34. 
    35. /*
    36. 	 * channelInactive
    37. 	 * 
    38. 	 * channel 	通道
    39. 	 * Inactive 不活跃的
    40. 	 * 
    41. 	 * 当客户端主动断开服务端的链接后,这个通道就是不活跃的。也就是说客户端与服务端的关闭了通信通道并且不可以传输数据
    42. 	 * 
    43. 	 */
    44. publicvoid(ChannelHandlerContext)throwsException{
    45. 
    46. // 从channelGroup中移除,当有客户端退出后,移除channel。
    47. MyChannelHandlerPool.channelGroup.remove(ctx.channel());
    48. 
    49. System.out.println(ctx.channel().localAddress().toString()+" channelInactive");
    50. 
    51. }
    52. 
    53. /*
    54. 	 * channelRead
    55. 	 * 
    56. 	 * channel 通道
    57. 	 * Read    读
    58. 	 * 
    59. 	 * 简而言之就是从通道中读取数据,也就是服务端接收客户端发来的数据
    60. 	 * 但是这个数据在不进行解码时它是ByteBuf类型的后面例子我们在介绍
    61. 	 * 
    62. 	 */
    63. publicvoid(ChannelHandlerContext,Object)
    64. throwsException{
    65. 
    66. //注意此处已经不需要手工解码了
    67. System.out.println(ctx.channel().id()+""+newDate()+" "+msg);
    68. 
    69. //通知您已经链接上客户端[给客户端穿回去的数据加个换行]
    70. String="服务端收到:"+ctx.channel().id()+newDate()+" "+msg+"\r\n";
    71. 
    72. //收到信息后,群发给所有小伙伴
    73. MyChannelHandlerPool.channelGroup.writeAndFlush(str);
    74. }
    75. 
    76. /*
    77. 	 * channelReadComplete
    78. 	 * 
    79. 	 * channel  通道
    80. 	 * Read     读取
    81. 	 * Complete 完成
    82. 	 * 
    83. 	 * 在通道读取完成后会在这个方法里通知,对应可以做刷新操作
    84. 	 * ctx.flush()
    85. 	 * 
    86. 	 */
    87. publicvoid(ChannelHandlerContext)throwsException{
    88. .flush();
    89. }
    90. 
    91. /*
    92. 	 * exceptionCaught
    93. 	 * 
    94. 	 * exception	异常
    95. 	 * Caught		抓住
    96. 	 * 
    97. 	 * 抓住异常,当发生异常的时候,可以做一些相应的处理,比如打印日志、关闭链接
    98. 	 * 
    99. 	 */
    100. publicvoid(ChannelHandlerContext,Throwable)
    101. throwsException{
    102. .close();
    103. System.out.println("异常信息:\r\n"+cause.getMessage());
    104. }
    105. 
    106. 
    107. 
    108. }
    NettyServer.java
     
    1. package.itstack;
    2.  
    3. import.netty.bootstrap.ServerBootstrap;
    4. import.netty.channel.ChannelFuture;
    5. import.netty.channel.ChannelOption;
    6. import.netty.channel.EventLoopGroup;
    7. import.netty.channel.nio.NioEventLoopGroup;
    8. import.netty.channel.socket.nio.NioServerSocketChannel;
    9.  
    10. publicclassNettyServer{
    11.  
    12. publicstaticvoid(String[]){
    13. 
    14. try{
    15. System.out.println("服务端开启等待客户端链接");
    16. newNettyServer().bing(7397);
    17. }catch(Exception){
    18. .printStackTrace();
    19. }
    20. 
    21. }
    22. 
    23. publicvoid(int)throwsException{
    24. 
    25. EventLoopGroup=newNioEventLoopGroup();
    26. EventLoopGroup=newNioEventLoopGroup();
    27. 
    28. try{
    29. 
    30. ServerBootstrap=newServerBootstrap();
    31. .group(bossGroup,);
    32. .channel(NioServerSocketChannel.class);
    33. .option(ChannelOption.SO_BACKLOG,1024);
    34. .childHandler(newChildChannelHandler());
    35. 
    36. // 绑定端口
    37. ChannelFuture=.bind(port).sync();
    38. 
    39. // 等待服务端监听端口关闭
    40. .channel().closeFuture().sync();
    41. 
    42. }finally{
    43. 
    44. // 优雅的退出
    45. .shutdownGracefully();
    46. .shutdownGracefully();
    47. }
    48. 
    49. }
    50. 
    51. }
    1、启动NettyServer 
    2、控制台输出:
    ----------------------------------------------
    服务端开启等待客户端链接
    ----------------------------------------------
    3、开启2个以上客户端模拟软件
     
    
    	4、
    
    
    	服务端端控制台输出:
    
    
    	----------------------------------------------
    
    
    	报告
    
    信息:有一客户端链接到本服务端
    
    IP:user-PC
    
    Port:7397
    
    报告完毕
    
    user-PC/192.168.30.223:7397 channelActive
    
    defa23d9Tue Dec 30 16:54:51 CST 2014 群号:5360692
    
    defa23d9Tue Dec 30 16:54:51 CST 2014 群号:5360692
    
    defa23d9Tue Dec 30 16:54:52 CST 2014 群号:5360692
    
    defa23d9Tue Dec 30 16:54:53 CST 2014 群号:5360692
    
    报告
    
    信息:有一客户端链接到本服务端
    
    IP:localhost.localdomain

    Port:7397

    报告完毕
    
    localhost.localdomain/127.0.0.1:7397 channelActive
    
    5f735249Tue Dec 30 16:55:02 CST 2014 1
    
    5f735249Tue Dec 30 16:55:03 CST 2014 1
    
    5f735249Tue Dec 30 16:55:04 CST 2014 1
    
    5f735249Tue Dec 30 16:55:04 CST 2014 1
    
    5f735249Tue Dec 30 16:55:04 CST 2014 1
    
    5f735249Tue Dec 30 16:55:05 CST 2014 1
    
    5f735249Tue Dec 30 16:55:05 CST 2014 1
    
    5f735249Tue Dec 30 16:55:05 CST 2014 1
    
    5f735249Tue Dec 30 16:55:05 CST 2014 1
    defa23d9Tue Dec 30 16:55:10 CST 2014

    其中一个客户端控制输出:

    ---------------------------------------------
    
    1. 您已经开启与服务端链接Dec3016:54:492014-PC/192.168.30.223:7397
    2. 服务端收到:defa23d9Tue Dec3016:54:512014群号:5360692
    3.  
    4. 服务端收到:defa23d9Tue Dec3016:54:512014群号:5360692
    5.  
    6. 服务端收到:defa23d9Tue Dec3016:54:522014群号:5360692
    7.  
    8. 服务端收到:defa23d9Tue Dec3016:54:532014群号:5360692
    9.  
    10. 服务端收到:5f735249TueDec3016:55:0220141
    11.  
    12. 服务端收到:5f735249TueDec3016:55:0320141
    13.  
    14. 服务端收到:5f735249TueDec3016:55:0420141
    15.  
    16. 服务端收到:5f735249TueDec3016:55:0420141
    17.  
    18. 服务端收到:5f735249TueDec3016:55:0420141
    19.  
    20. 服务端收到:5f735249TueDec3016:55:0520141
    21.  
    22. 服务端收到:5f735249TueDec3016:55:0520141
    23.  
    24. 服务端收到:5f735249TueDec3016:55:0520141
    25.  
    26. 服务端收到:5f735249TueDec3016:55:0520141
    27.  
    28. 服务端收到:defa23d9Tue Dec3016:55:102014 
    29. ---------------------------------------------