netty服务器,客户端的开发

59 篇文章 0 订阅

1.netty

是一种网络传输框架,是对NIO的一个封装,一般用于游戏开发,与此相媲美的是MINA。作者都是同一个人。

2.netty的简单原理



从上图可以很清晰的看到客户端要与服务通信,必须要一个通道与一个端口才能使其相互通信,boos线程池接收数据分配任务给work线程池进行处理业务逻辑

3.客户端与服务器的通道的粘包与拆包的解决方案,
什么是粘包:
一般所谓的TCP粘包是在一次接收数据不能完全地体现一个完整的消息数据。TCP通讯为何存在粘包呢?主要原因是TCP是以流的方式来处理数据,再加上网络上MTU(指一种通信协议的某一层上面所能通过的最大数据包大小(以字节为单位))的往往小于在应用处理的消息数据,所以就会引发一次接收的数据无法满足消息的需要,导致粘包的存在。处理粘包的唯一方法就是制定应用层的数据通讯协议,通过协议来规范现有接收的数据是否满足消息数据的需要。

解决办法

1、消息定长,报文大小固定长度,不够空格补全,发送和接收方遵循相同的约定,这样即使粘包了通过接收方编程实现获取定长报文也能区分。

2、包尾添加特殊分隔符,例如每条报文结束都添加回车换行符(例如FTP协议)或者指定特殊字符作为报文分隔符,接收方通过特殊分隔符切分报文区分。

3、将消息分为消息头和消息体,消息头中包含表示信息的总长度(或者消息体长度)的字段

4、更复杂的自定义应用层协议

下面的则为3的分析




实例如下:
服务器:


  1. package cn.horace.netty.server;  
  2.   
  3. import io.netty.bootstrap.ServerBootstrap;  
  4.   
  5. /** 
  6.  * Netty服务器 
  7.  *  
  8.  * @author Administrator 
  9.  *  
  10.  */  
  11. public class NettyServer {  
  12.   
  13.     // 服务器监听的端口  
  14.     private static final int PORT = 1588;  
  15.   
  16.     public static void main(String[] args) {  
  17.   
  18.         // 创建服务器引导对象  
  19.         ServerBootstrap bootstrap = new ServerBootstrap();  
  20.   
  21.         // 创建“线程池”  
  22.         NioEventLoopGroup bossGroup = new NioEventLoopGroup();  
  23.         NioEventLoopGroup workGroup = new NioEventLoopGroup();  
  24.   
  25.         try {  
  26.             // 设置“线程池”  
  27.             bootstrap.group(bossGroup, workGroup);  
  28.   
  29.             // 告诉Netty它也使用NioServerSocketChannel作为连接通道  
  30.             bootstrap.channel(NioServerSocketChannel.class);  
  31.   
  32.             // 当客户端向服务器发送数据的时候都会经过这个方法  
  33.             bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {  
  34.   
  35.                 @Override  
  36.                 protected void initChannel(SocketChannel socketChannel) throws Exception {  
  37.   
  38.                     /** 
  39.                      * 解码器 
  40.                      *  
  41.                      * 1、maxFrameLength:最大帧长度值,数据包的最大长度 
  42.                      * 2、lengthFieldOffset:长度字段的偏移量 
  43.                      * 3、lengthFieldLength:长度子字段的长度值 4、lengthAdjustment:长度调节值 
  44.                      * 5、initialBytesToStrip:跳过长度字节值 
  45.                      * 6、failFast:当数据包超过maxFrameLength值时 
  46.                      * ,是否立即抛出异常,true:立即抛出异常,false:把数据接收完毕后在抛出异常 
  47.                      */  
  48.                     socketChannel.pipeline().addLast(  
  49.                             new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0404false));  
  50.   
  51.                     /** 
  52.                      * 编码器 
  53.                      *  
  54.                      * 1、lengthFieldLength:长度字段的长度值 
  55.                      * 2、lengthIncludesLengthFieldLength:如果为true,那么数据包的长度 = 
  56.                      * 长度字段的长度 + 实际数据的长度 
  57.                      */  
  58.                     socketChannel.pipeline().addLast(new LengthFieldPrepender(40false));  
  59.   
  60.                     // 数据包的处理器对象  
  61.                     socketChannel.pipeline().addLast(new ServerMessageHandler());  
  62.                 }  
  63.   
  64.             });  
  65.   
  66.             // 同步绑定端口,如果绑定端口失败,则会抛出异常  
  67.             ChannelFuture future = bootstrap.bind(PORT).sync();  
  68.   
  69.             System.out.println("Server start at " + PORT + ".");  
  70.   
  71.             // 同步监听服务器端口的关闭  
  72.             future.channel().closeFuture().sync();  
  73.         } catch (Exception e) {  
  74.             e.printStackTrace();  
  75.         } finally {  
  76.             // 优雅的释放线程资源,并关闭服务器  
  77.             bossGroup.shutdownGracefully();  
  78.             workGroup.shutdownGracefully();  
  79.         }  
  80.     }  
  81. }  

客户端:

  1. package cn.horace.netty.client;  
  2.   
  3. import io.netty.bootstrap.Bootstrap;  
  4.   
  5. /** 
  6.  * Netty客户端 
  7.  *  
  8.  * @author Administrator 
  9.  *  
  10.  */  
  11. public class NettyClient {  
  12.   
  13.     // 服务器监听的端口  
  14.     private static final int PORT = 1588;  
  15.     private static final String HOST = "127.0.0.1";  
  16.   
  17.     public static void main(String[] args) {  
  18.   
  19.         // 创建客户端引导对象  
  20.         Bootstrap bootstrap = new Bootstrap();  
  21.   
  22.         // 创建“线程池”  
  23.         NioEventLoopGroup group = new NioEventLoopGroup();  
  24.   
  25.         try {  
  26.             // 设置“线程池”  
  27.             bootstrap.group(group);  
  28.   
  29.             // 告诉Netty它也使用NioSocketChannel作为连接通道  
  30.             bootstrap.channel(NioSocketChannel.class);  
  31.   
  32.             // 当客户端向服务器发送数据的时候都会经过这个方法  
  33.             bootstrap.handler(new ChannelInitializer<SocketChannel>() {  
  34.   
  35.                 // 这个方法一般是用于做数据包的解码与编码操作  
  36.                 @Override  
  37.                 protected void initChannel(SocketChannel socketChannel) throws Exception {  
  38.   
  39.                     /** 
  40.                      * 解码器 
  41.                      *  
  42.                      * 1、maxFrameLength:最大帧长度值,数据包的最大长度 
  43.                      * 2、lengthFieldOffset:长度字段的偏移量 
  44.                      * 3、lengthFieldLength:长度子字段的长度值 4、lengthAdjustment:长度调节值 
  45.                      * 5、initialBytesToStrip:跳过长度字节值 
  46.                      * 6、failFast:当数据包超过maxFrameLength值时 
  47.                      * ,是否立即抛出异常,true:立即抛出异常,false:把数据接收完毕后在抛出异常 
  48.                      */  
  49.                     socketChannel.pipeline().addLast(  
  50.                             new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0404false));  
  51.   
  52.                     /** 
  53.                      * 编码器 
  54.                      *  
  55.                      * 1、lengthFieldLength:长度字段的长度值 
  56.                      * 2、lengthIncludesLengthFieldLength:如果为true,那么数据包的长度 = 
  57.                      * 长度字段的长度 + 实际数据的长度 
  58.                      */  
  59.                     socketChannel.pipeline().addLast(new LengthFieldPrepender(40false));  
  60.   
  61.                     // 数据包的处理器对象  
  62.                     socketChannel.pipeline().addLast(new ClientMessageHandler());  
  63.                 }  
  64.             });  
  65.   
  66.             // 连接服务器  
  67.             ChannelFuture future = bootstrap.connect(new InetSocketAddress(HOST, PORT)).sync();  
  68.   
  69.             System.out.println("Conennect server success.");  
  70.               
  71.             // 同步监听服务器端口的关闭  
  72.             future.channel().closeFuture().sync();  
  73.         } catch (Exception e) {  
  74.             e.printStackTrace();  
  75.         } finally {  
  76.             // 优雅的释放线程资源,并关闭客户端  
  77.             group.shutdownGracefully();  
  78.         }  
  79.     }  
  80. }  

注意:别忘了添加netty-all-4.0.31.Final.jar哦,没有jar可到netty官网http://netty.io/下载,或者前往http://mvnrepository.com/search?q=netty下载
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值