本文所使用JDK7和netty5.0为基础。Netty5.0

Netty 服务端开发

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;/*** Created by lianpeng on 2016/12/6.*/
public class NettyService {private static final int PORT = 30088;public static void start() {//事件循环组将网络编程的线程处理部分很好的封装起来EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workGroup = new NioEventLoopGroup();//启动服务端必须实例化ServerBootstrap bootstrap = new ServerBootstrap();//指定使用的事件循环组,该组用于接受连接、接收/发送数据,等等//可以指定两个事件循环组,分别用于接受连接、读写数据bootstrap.group( bossGroup, workGroup )//使用非阻塞的套接字传输,必须指定此服务器通道类型,以监听并处理客户端连接.channel( NioServerSocketChannel.class )//当连接被接受后,会创建NioServerSocketChannel的子通道SocketChannel//childHandler方法用于指定子通道的处理器,通常为ChannelInitializer.handler( new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel( SocketChannel ch ) throws Exception {//管道(Pipeline)持有某个通道的全部处理器ChannelPipeline pipeline = ch.pipeline();//添加一个处理器pipeline.addLast();}} );try {//绑定端口,等待直到成功ChannelFuture f = bootstrap.bind( PORT ).sync();//等待服务器通道被关闭f.channel().closeFuture().sync();} catch ( InterruptedException e ) {e.printStackTrace();} finally {//关闭事件循环,释放相关资源(包括创建的线程)bossGroup.shutdownGracefully();workGroup.shutdownGracefully();}}}class nettyServHandle extends ChannelHandlerAdapter {/*** 当从通道读取到数据后,会执行该回调* 注意:数据可能碎片化,分若干次读取,这种情况下,该回调会被执行多次*/public void channelRead( ChannelHandlerContext ctx, Object msg ) {ByteBuf buf = (ByteBuf) msg;//注意这里不一定能收到完整的消息//将接收到的数据写回去,注意这里还没有将数据刷空以发送到对端(peer)//当前方法不使用channelRead0的原因:write可能在channelRead返回前尚未完成(因为异步)//如果使用channelRead0,那么msg对应的ByteBuf将被自动释放(release)ctx.write( msg );}/*** 当读取数据完毕(没有更多数据可读)后,会执行该回调*/public void channelReadComplete( ChannelHandlerContext ctx ) {//刷空所有数据,并在执行完毕后,关闭通道ctx.writeAndFlush( Unpooled.EMPTY_BUFFER ).addListener( ChannelFutureListener.CLOSE );}/*** 当发生任何异常时,执行该回调* 至少应当有一个通道处理器覆盖此方法,以实现必要的异常处理*/public void exceptionCaught( ChannelHandlerContext ctx, Throwable cause ) {//关闭通道ctx.close();}
}

Netty 客户端开发

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.CharsetUtil;import java.net.InetSocketAddress;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import cc.gmem.study.network.basic.Helper;public class NettyClient
{private static final Logger LOGGER = LoggerFactory.getLogger( NettyClient.class );private final String        host;private final int           port;public NettyClient( String host, int port ){this.host = host;this.port = port;}public void start() throws Exception{EventLoopGroup group = new NioEventLoopGroup();try{//要启动客户端,必须实例化下面这个实例Bootstrap b = new Bootstrap();b//指定事件循环组.group( group )//指定非阻塞的套接字通道类.channel( NioSocketChannel.class )//指定需要连接的服务器.remoteAddress( new InetSocketAddress( host, port ) )//指定通道的处理器,一旦连接成功就会调用此处理器.handler( new ChannelInitializer() {public void initChannel( SocketChannel ch ) throws Exception{//在通道的尾部添加一个处理器ch.pipeline().addLast( new EchoClientHandler() );}} );//连接、等待直到连接成功ChannelFuture f = b.connect().sync();//等待直到客户端通道被关闭f.channel().closeFuture().sync();}finally{//关闭事件循环,释放相关资源(包括创建的线程)group.shutdownGracefully().sync();}}public static void main( String[] args ) throws Exception{new EchoClient( Helper.DEFAULT_HOST, Helper.DEFAULT_PORT ).start();}@Sharablepublic class NettyClientHandler extends SimpleChannelInboundHandler{/*** 一旦与服务器的连接建立,即调用此回调*/public void channelActive( ChannelHandlerContext ctx ){//发送一个简单的消息给服务器//Unpooled是一个工具类,可以分配新的缓冲,或者包装已经存在的字节数组、字节缓冲、字符串//copiedBuffer方法可以根据指定的字符串和编码方式,创建一个大端(big-endian)的字节缓冲//这里的几个汉字和标点共计21字节ByteBuf msg = Unpooled.copiedBuffer( "服务器,你好!", CharsetUtil.UTF_8 );//写入数据并刷空,如果不刷空,数据可能存在于本地缓冲,不发送给服务器ctx.writeAndFlush( msg );}/*** 从服务器接收到数据后,调用此回调。channelRead0会自动的释放(减少引用计数,如果为0则解构并回收)ByteBuf对象* 需要注意的是:接收到的字节可能是碎片化的(channelRead0),虽然上面发送了21字节给服务器* 但是可能分多次读取,例如:第一次读取10字节,第二次读取11字节。因此该回调可能被调用多次* 唯一能保证的是:在使用TCP或其它面向流的协议的情况下,数据被读取的顺序有保证*/public void channelRead0( ChannelHandlerContext ctx, ByteBuf in ){int count = in.readableBytes();//可以获取本次可读的字节数ByteBuf buf = in.readBytes( count ); //读取为字节缓冲Object msg = buf.toString( CharsetUtil.UTF_8 );//转换为字符串形式LOGGER.debug( "Client received: {}", msg );}public void exceptionCaught( ChannelHandlerContext ctx, Throwable cause ){ctx.close();}}
}

Netty 解决tcp粘包和分包

TCP以流的方式进行数据传输,上层的应用程序为了对消息进行区分,往往采样一下此种方式

1.消息长度固定,累计读取到长度总和为LEN的报文后,就认为读取到了一个完整的消息;讲计数器,讲计数器职位重新开始读下一个数据包;

2.将回车符作为消息的结束符,例如:FTP协议,这种方式使用比较广泛

3.将特殊字符作为消息的结束符;

4.通过消息头定义长度字段来标示消息的总长度。

Netty对上面四种应用做了统一的抽象,提供了四种解码器来解决对应问题。

1. StringDecoder     将消息解码成String类型方便读取;

2.LineBasedFrameDecoder    以换行符为结束标记的解码器,工作原理是依次遍历ByteBuf中的可读字节,判读是否是“\n”或“\r\n”;

pipeline.addLast(new LineBasedFrameDecoder( 1024 ) );

3.DelimiterBasedFrameDecoder   以特殊字符为消息结束符的解码器;

ByteBuf delimiter = Unpooled.copiedBuffer( "$_".getBytes() );
//第一个参数表示消息的最大长度,当消息读取到最大长度后任然没找见分割符,就抛出
//TooLongFrameException异常,防止异常码流缺失导致的内存溢出
pipeline.addLast( "framer", new DelimiterBasedFrameDecoder( Integer.MAX_VALUE, Delimiters.nulDelimiter() ) );

4.FixedBasedFrameDecoder   以固定长度进行解码,不管一次接受多少数据包,他都是按设定的长度进行解码;

pipeline.addLast( new FixedBasedFrameDecoder( 1024 ) );

netty基础知识2相关推荐

  1. Netty5基础知识介绍及简单使用

    Netty基础知识 Netty 是一个 NIO client-server(客户端服务器)框架, 使用 Netty 可以快速开发网络应用,例如服务器和客户端协议.Netty 提供了一种新的方式来使开发 ...

  2. java基础知识点_「Java面试题/知识点精华集」20000+字的Java基础知识篇(2020最新版) !

    " 本文已经收录进我的 79K Star 的 Java 开源项目 JavaGuide:https://github.com/Snailclimb/JavaGuide (「Java学习+面试指 ...

  3. Netty基础系列(1) --linux网路I/O模型

    引言 我一直认为对于java的学习,掌握基础的性价比要远远高于使用框架,而基础知识中对于网络相关知识的掌握也是重中之重.对于一个java程序来说,无论是工作中还是面试,对于Netty的掌握都是及其重要 ...

  4. IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

    1.引言 消息是互联网信息的一种表现形式,是人利用计算机进行信息传递的有效载体,比如即时通讯网坛友最熟悉的即时通讯消息就是其具体的表现形式之一. 消息从发送者到接收者的典型传递方式有两种: 1)一种我 ...

  5. Java基础知识回顾之七 ----- 总结篇

    前言 在之前Java基础知识回顾中,我们回顾了基础数据类型.修饰符和String.三大特性.集合.多线程和IO.本篇文章则对之前学过的知识进行总结.除了简单的复习之外,还会增加一些相应的理解. 基础数 ...

  6. c++ 多个线程操作socket要同步吗_基础知识深化:NIO优化原理和Tomcat线程模型

    1.I/O阻塞 书上说BIO.NIO等都属于I/O模型,但是I/O模型这个范围有点含糊,我为此走了不少弯路.我们日常开发过程中涉及到NIO模型应用,如Tomcat.Netty中等线程模型,可以直接将其 ...

  7. ❤️六W字《计算机基础知识》(二)(建议收藏)❤️

    上一篇: ❤️六W字<计算机基础知识>(一)❤️  51. Access是一种____数据库管理系统. A.发散型 B.集中型  C.关系型  D.逻辑型 52. 用高级程序设计语言编写的 ...

  8. ❤️六W字《计算机基础知识》(一)(建议收藏)❤️

    计算机简介:         计算机(computer)俗称电脑,是现代一种用于高速计算的电子计算机器,可以进行数值计算,又可以进行逻辑计算,还具有存储记忆功能.是能够按照程序运行,自动.高速处理海量 ...

  9. IT:后端进阶技术路线图(初级→中级→高级)、后端开发工程师(技术方向分类之后台业务开发/中间件/内核/分布式架构)基础知识简介、技术路线/技术趋势指南(如何选择自己的技术方向)之详细攻略

    IT:后端进阶技术路线图(初级→中级→高级).后端开发工程师(技术方向分类之后台业务开发/中间件/内核/分布式架构)基础知识简介.技术路线/技术趋势指南(如何选择自己的技术方向)之详细攻略 目录 后端 ...

最新文章

  1. android 动态人脸识别码,android OpenCV研究之动态人脸识别
  2. UVA 10494 - If We Were a Child Again(高精度除法和取余)
  3. 【 Notes 】 AGPS or Assisted GPS
  4. OS_CORE.C(4)
  5. abstract类中不可以有private的成员_别再说你不懂java面向对象了,阿里P7大佬一次性给你讲的明明白白
  6. 翻译:用户变量(User-Defined Variable)(已提交到MariaDB官方手册)
  7. python中获取异常描述与else用法
  8. python 简单trace 过滤处理
  9. defaultcharacterset mysql_C# .Net+MySQL组合开发Character set ‘gbk’ is not supported的解决方法...
  10. C#时间的味道——任时光匆匆我只在乎你
  11. Kconfig的两种用法
  12. html中css 样式怎么写,css样式怎么写?
  13. CentOS6.5 开启防火墙iptables端口,如3306,8080
  14. 决策树注意事项和参数调节
  15. 使用开源软件FFmpeg将各种格式视频转换成MP4视频格式(最简单方法)
  16. 神州优车推出智慧交通开放平台 3年将投入3亿元
  17. jar包启动调用外系统文件上传,无法生成文件,报org.springframework.web.client. ResourceAccessException: I/0 error on POST
  18. Kafka的灵魂伴侣Logi-KafkaManger(2)之kafka针对Topic粒度的配额管理(限流)
  19. html 复选框 不能编辑,javascript-jqGrid-复选框编辑无法编辑所选行
  20. 困扰我多年的印度人点头摇头问题

热门文章

  1. HTML鼠标悬浮空心圆点切换图片,js实现鼠标切换图片(无定时器)
  2. VS error c2504未定义基类
  3. 今天我要对人人商城多商户,和分销功能动动刀,使用起来会更香吧
  4. Flink学习1-基础概念
  5. 一篇就懂SpringBoot邮箱功能
  6. linux内核同步机制-RCU(3)
  7. mysql的索引文件_MySQL:索引在磁盘上的存储
  8. 建议收藏丨你想了解的动捕内容全在这儿!
  9. HDU:6697-Closest Pair of Segments(空间内的最近线段)
  10. 老司机 iOS 周报 #4