Netty入门实例-使用POJO代替ByteBuf

到目前为止,我们上面几篇教程中的所有例子都使用ByteBuf作为协议消息的主要数据结构。 在本节中,我们将改进TIME协议的客户端和服务器示例,让它们使用POJO来代替原来的ByteBuf。

ChannelHandler中使用POJO的优点是显而易见的; 处理程序将从ByteBuf中提取信息的代码,将从处理程序中分离出来,变得更易维护和可重用。 在TIME客户端和服务器示例中,我们只读取一个32位整数,它不是直接使用ByteBuf来解码转换的。在实现真实世界协议时,这是必须要进行分离的。

首先,我们定义一个名为 UnixTime 的新类型(一个简单的Java类)。

package cn.netty.timepojo;

import java.util.Date;public class UnixTime {

    private final long value;

    public UnixTime() {
        this(System.currentTimeMillis() / 1000L + 2208988800L);
    }

    public UnixTime(long value) {
        this.value = value;
    }

    public long value() {
        return value;
    }

    @Override
    public String toString() {
        Date date = new Date((value() - 2208988800L) * 1000L);
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = formatter.format(date);
        return dateString;
    }
}


我们现在来修改时间解码器(TimeDecoder)来生成UnixTime,而不是ByteBuf

@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
    if (in.readableBytes() < 4) {
        return;
    }

    out.add(new UnixTime(in.readUnsignedInt()));
}


使用更新的解码器,TimeClientHandler不再使用ByteBuf:

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
    UnixTime m = (UnixTime) msg;
    System.out.println(m);
    ctx.close();
}


怎么样?看起更简单和优雅,对吧? 相同地也可以应用在服务器端。现在我们首先更新TimeServerHandler中的代码:

@Override
public void channelActive(ChannelHandlerContext ctx) {
    ChannelFuture f = ctx.writeAndFlush(new UnixTime());
    f.addListener(ChannelFutureListener.CLOSE);
}


现在,唯一缺少的是一个编码器,它是一个ChannelOutboundHandler的实现,是将UnixTime转换回ByteBuf。 它比编写解码器简单得多,因为在编码消息时不需要处理数据包分段和组合。

package cn.sxt.netty.timepojo;

public class TimeEncoder extends ChannelOutboundHandlerAdapter {
    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
        UnixTime m = (UnixTime) msg;
        ByteBuf encoded = ctx.alloc().buffer(4);
        encoded.writeInt((int)m.value());
        ctx.write(encoded, promise); // (1)
    }
}


  1. 在这一行有很多重要的东西。
    首先,我们按原样传递原始的ChannelPromise,以便Netty将编码数据实际写入时将其标记为成功或失败。
    第二步,我们没有调用ctx.flush()。 有一个单独的处理程序方法void flush(ChannelHandlerContext ctx),它用于覆盖flush()操作。

要进一步简化,可以使用MessageToByteEncoder

public class TimeEncoder extends MessageToByteEncoder<UnixTime> {
    @Override
    protected void encode(ChannelHandlerContext ctx, UnixTime msg, ByteBuf out) {
        out.writeInt((int)msg.value());
    }
}


剩下的最后一个任务是在TimeServerHandler之前将TimeEncoder插入到服务器端的ChannelPipeline中,这里将留作一个简单的练习吧。


2019-04-20 15:44

相关知识点

开源项目

知识点

相关教程

更多

Netty入门实例-时间服务器

Netty中服务器和客户端之间最大的和唯一的区别是使用了不同的Bootstrap和Channel实现

Netty入门实例-编写服务器端程序

channelRead()处理程序方法实现如下

Spring boot入门实例

入门实例是基于maven工程,主要配置: spring boot 父节点依赖,引入这个之后相关的引入就不需要添加version配置,spring boot会自动选择最合适的版本进行添加。 <parent>   <groupId>org.springframework.boot</groupId>   <artifactId>spring-boot-s

vue 入门实例


                            

solr入门之SolrServer实例化方式

solr入门之SolrServer实例化方式 (2013-06-19 18:04:14)   转载▼         随着solr版本的不断升级, 差异越来越大, 从以前的 solr1.2 到现在的 solr4.3, 无论是类还是功能都有很大的变换,为了能及时跟上新版本的步伐, 在此将新版本的使用做一个简单的入门说明: Solr3.6版本 SolrServer实例化类型有httpClient,和本

Activiti入门程序-启动流程实例

RuntimeService:执行管理,包括启动、推进、删除流程实例等操作  RuntimeService是activiti的流程执行服务类。可以从这个服务类中获取很多关于流程执行相关的信息  调用processEngine的getRuntimeService方法获取RuntimeService对象 调用RuntimeService的相关方法可以启动流程实例有以下方法 启动流程实例示例程序: /*

iText生成PDF入门实例

最近想把网站的文章导出为PDF文件,所以又得学学怎样导出PDF。iText是用于生成PDF文档的一个java类库。通过iText不仅可以生成PDF文档,而且可以将HTML网页转化为PDF文件,同时它可以很方便的和web或者其他应用整合使用。

Spring MVC 入门实例教程


                            

[Netty 1] 初识Netty

1. 简介 最早接触netty是在阅读Zookeeper源码的时候,后来看到Storm的消息传输层也由ZMQ转为Netty,所以决心好好来研究和学习一下netty这个框架。 Netty项目地址:http://netty.io/index.html Github项目: https://github.com/netty/netty Netty是一个异步的、事件驱动的网络应用框架,基于它能够快速开发高性

Lucene学习笔记之四:lucene入门实例

根据Lucene学习笔记之三:全文搜索详解,搭建lucene入门实例。主要内容包括建立索引和搜索,分词贯穿其中。lucene建立索引,信息源:要采集,必须有信息源,在这里我们就以读取硬盘中一个文件夹下所有的文件(File)充当信息源。

Activiti入门程序-查看历史实例信息

HistoryService:查询历史信息的服务。在一个流程执行完成后,这个对象为我们提供查询历史信息。     历史实例查询包括:  1、历史流程实例查询 HistoricProcessInstanceQuery  HistoricProcessInstanceQuery hpiQuery = service.createHistoricProcessInstanceQuery();   2、查

构建Disruptor实例-生产消费模型完成整个入门示例

初始化Disruptor,构建Disruptor只要需要以下几个参数:1 eventFactory: 消息(event)工厂对象,2 ringBufferSize: 容器的长度,​3 executor: 线程池(建议使用自定义线程池) RejectedExecutionHandler,​4 ProducerType: 单生产者 还是 多生产者, ​5 waitStrategy: 等待策略2、初始化好Disruptor之后,通过该对象的handleEventsWith添加消费者的监听。3、然后启动D...

Netty环境配置

netty是一个java事件驱动的网络通信框架,也就是一个jar包,只要在项目里引用即可。

Hadoop入门—Linux下伪分布式计算的安装与wordcount的实例展示

开始研究一下开源项目Hadoop,因为根据本人和业界的一些分析,海量数据的分布式并行处理是趋势,咱不能太落后,虽然开始有点晚,呵呵。首先就是安装和一个入门的小实例的讲解,这个恐怕是我们搞软件开发的,最常见也最有效率地入门一个新鲜玩意的方式了,废话不多说开始吧。 本人是在Ubuntu下进行实验的,java和ssh安装就不在这里讲了,这两个是必须要安装的,好了我们进入主题安装hadoop: 1.下载h

Netty开发环境配置

最新版本的Netty 4.x和JDK 1.6及更高版本

最新教程

更多

redis从库只读设置-redis集群管理

默认情况下redis数据库充当slave角色时是只读的不能进行写操作,如果写入,会提示以下错误:READONLY You can't write against a read only slave.  127.0.0.1:6382> set k3 111  (error) READONLY You can't write against a read only slave. 如果你要开启从库

Netty环境配置

netty是一个java事件驱动的网络通信框架,也就是一个jar包,只要在项目里引用即可。

Netty基于流的传输处理

​在TCP/IP的基于流的传输中,接收的数据被存储到套接字接收缓冲器中。不幸的是,基于流的传输的缓冲器不是分组的队列,而是字节的队列。 这意味着,即使将两个消息作为两个独立的数据包发送,操作系统也不会将它们视为两个消息,而只是一组字节(有点悲剧)。 因此,不能保证读的是您在远程定入的行数据

Netty入门实例-时间服务器

Netty中服务器和客户端之间最大的和唯一的区别是使用了不同的Bootstrap和Channel实现

Netty入门实例-编写服务器端程序

channelRead()处理程序方法实现如下

Netty开发环境配置

最新版本的Netty 4.x和JDK 1.6及更高版本

电商平台数据库设计

电商平台数据库表设计:商品分类表、商品信息表、品牌表、商品属性表、商品属性扩展表、规格表、规格扩展表

HttpClient 上传文件

我们使用MultipartEntityBuilder创建一个HttpEntity。 当创建构建器时,添加一个二进制体 - 包含将要上传的文件以及一个文本正文。 接下来,使用RequestBuilder创建一个HTTP请求,并分配先前创建的HttpEntity。

MongoDB常用命令

查看当前使用的数据库    > db    test  切换数据库   > use foobar    switched to db foobar  插入文档    > post={"title":"领悟书生","content":"这是一个分享教程的网站","date":new

快速了解MongoDB【基本概念与体系结构】

什么是MongoDB MongoDB is a general purpose, document-based, distributed database built for modern application developers and for the cloud era. MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。

windows系统安装MongoDB

安装 下载MongoDB的安装包:mongodb-win32-x86_64-2008plus-ssl-3.2.10-signed.msi,按照提示步骤安装即可。 安装完成后,软件会安装在C:\Program Files\MongoDB 目录中 我们要启动的服务程序就是C:\Program Files\MongoDB\Server\3.2\bin目录下的mongod.exe,为了方便我们每次启动,我

Spring boot整合MyBatis-Plus 之二:增删改查

基于上一篇springboot整合MyBatis-Plus之后,实现简单的增删改查 创建实体类 添加表注解TableName和主键注解TableId import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baom

分布式ID生成器【snowflake雪花算法】

基于snowflake雪花算法分布式ID生成器 snowflake雪花算法分布式ID生成器几大特点: 41bit的时间戳可以支持该算法使用到2082年 10bit的工作机器id可以支持1024台机器 序列号支持1毫秒产生4096个自增序列id 整体上按照时间自增排序 整个分布式系统内不会产生ID碰撞 每秒能够产生26万ID左右 Twitter的 Snowflake分布式ID生成器的JAVA实现方案

Spring boot整合mybatis plus

快速了解mybatis plus 是对Mybatis框架的二次封装和扩展 纯正血统:完全继承原生 Mybatis 的所有特性 最少依赖:仅仅依赖Mybatis以及Mybatis-Spring 性能损耗小:启动即会自动注入基本CURD ,性能无损耗,直接面向对象操作 自动热加载:Mapper对应的xml可以热加载,大大减少重启Web服务器时间,提升开发效率 性能分析:自带Sql性能分析插件,开发测试

Docker 容器创建并运行MySQL

下载MySQL镜像:docker pull centos/mysql‐57‐centos7(docker默认从国外的镜像网站拉取镜像,速度很慢。可以使用国内的阿里云镜像加速站点提升镜像拉取速度)。运行容器:docker run -di --name=mysql-test -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root centos/mysql-57-centos7,docker run 命令具体使用方法可以使用 docker run --help 查看