java-Netty学习(2)

任务:

创建开发环境
编写一个Echo服务器和客户端
编译测试应用

框架:


同时连到一个服务器的多个客户端。理论上,可支持的客户端数量是受可支配系统资源限制的(以及在用的JDK版本带来的限制)。Echo客户端和服务器之间的交互非常简单; 客户端建立一个连接后,它送一条或者多条消息到服务器,然后服务器再将该消息送回客户端。虽然这个交互看起来不那么实用,但却是一个典型的客户端/服务器系统请求-响应交互过程的示例。

服务器端:

所有的Netty服务器都需要:

至少一个ChannelHandler—这个组件实现了服务器如何处理从客户端收到的数据—它的业务逻辑。
Bootstrapping—这是配置服务器的启动代码。至少要做的是,它把服务器绑到一个可以监听连接请求的端口上。
ChannelInboundHandler:定义了作用于输入事件的方法。这个简单的应用只需要这个接口的一些方法,所以用子类ChannelInboundHandlerAdapter就足够了,这个子类提供了ChannelInboundHandler的缺省实现。

channelRead()—每次收到消息时被调用
channelReadComplete()—用来通知handler上一个ChannelRead()是被这批消息中的最后一个消息调用
exceptionCaught()—在读操作异常被抛出时被调用

ChannelInboundHandlerAdapter有简明直接的API,每个方法都可以被重写(overridden),钩挂到(hook into)event生命周期的适当时间点。因为你需要处理所有收到的数据,所以你得重写channelRead()。在这个服务器里,你只要简单地把收到的消息送回远端。
重写exceptionCaught()让你可以对任何Throwable的子类型做出反应—在这里,你打印了这个异常然后关闭了这个连接。一个更加复杂的应用也许会试着从异常中恢复,但是在这个例子中,仅仅把连接关闭就向远端发出了错误已经发生的信号。
如果异常没有被捕获会发生什么?
每个Channel有一个对应的ChannelPipeline,这个ChannelPipeline有一串ChannelHandler实例。默认情况下,一个handler会传递某个handler方法的调用到下一个handler。所以,如果在这个传递链中exceptionCaught()没有实现,异常会一直走到ChannelPipeline的终点,然后被载入日志。因为这个原因,你的应用应该提供至少一个实现了exceptionCaught()的handler。
除了ChannelInboundHandlerAdapter,还有许多其他ChannelHandler子类和实现可以学习。ChannelHandlers被不同类型的events调用
应用程序通过实现或者扩展ChannelHandlers来钩挂到event的生命周期,并且提供定制的应用逻辑在结构上,ChannelHandlers解耦你的业务逻辑和网络代码。这会简化开发过程,因为代码会随着需求的变化而变化。

Bootstrapping服务器:
绑定到一个端口,服务器在这个端口上监听并且接收新的连接请求
配置Channels,来通知EchoServerHandler实例收到的消息
传输:传输层用来提供端对端或者主机对主机通信的服务。互联网通信是建立在TCP传输的基础上的。NIO传输(NIO transport)指的是一个类似于TCP传输的方式,不过它服务器端的性能增强由Java NIO的实现带来的。
EchoServerHandler实现业务逻辑
main()方法启动(bootstrap)服务器
以下是Bootstrapping中的必需步骤:
创建一个ServerBootstrap实例来启动和绑定服务器
创建并且分配一个NioEventLoopgroup实例来处理event,比如接受新的连接和读/写数据
指定本地InetSocketAddress到服务器绑定的端口
用一个EchoServerHandler实例来初始化每个新的Channel
调用ServerBootstrap.bind()来绑定服务器。

Echo客户端

连接到服务器
送出一条或者多条消息
对每条消息,等待并且从服务器收回一条同样的消息
关闭连接
和服务器一样,客户端会有一个ChannelInboundHandler来处理数据。扩展SimpleChannelInbondHandler类来处理所有的任务。
channelActive()—和服务器的连接建立起来后被调用
channelRead0()—从服务器收到一条消息时被调用
exceptionCaught()—处理过程中异常发生时被调用

SimpleChannelInboundHandler对比ChannelInboundHandler

你也许想知道为什么我们在客户端用了SimpleChannelInboundHandler,而不是EchoServerHandler中用的ChannelInboundHandlerAdapter。这和两个因素有关:业务逻辑如何处理消息,以及Netty如何管理资源。
在客户端,当channelRead0()完成时,你收到输入消息并且已经处理完成。当这个方法返回时,SimpleChannelInboundHandler会负责释放用于存放消息的ByteBuf的内存引用。
在EchoServerHandler中,你仍然要把输入的消息送回给发送端,而write()操作是异步的,直到channelRead()返回可能都没有完成(如代码清单2.1所示)。所以,EchoServerHandler扩展了ChannelInboundHandlerAdapter,不会在channelRead()返回的时候释放消息的内存引用。在writeAndFlush()被调用时,这个消息的内存引用会在EchoServerHandler的channelReadComplete()方法中被释放

bootstrapping一个客户端和bootstrapping一个服务器类似,不同于服务器绑定到一个监听端口,客户端用主机和端口参数来连接到一个远程地址,这里就是指Echo服务器.跟之前一样,使用的是NIO传输方式。注意,你在客户端和服务器中可以用不同的传输方式;比如,服务器端用NIO,在客户端用OIO。在第四章我们会分析一些因素和情景,让你为一个特定的使用案例选择一个特定传输方式。创建一个Bootstrap实例来初始化客户端
分配一个NioEventLoopgroup实例来处理事件,包括创建新的连接和处理输入输出数据
创建一个InetSocketAddress用于连接到服务器
当连接建立,一个EchoClientHandler会被装入pipeline
所有东西都创建完毕后,调用Bootstrap.connet()连接到远端。
完成客户端开发后,你可以接着编译和测试这个系统。

代码:

package server;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;

@Sharable
//可以被channel共享
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx,Object msg) throws java.lang.Exception {
        ByteBuf in = (ByteBuf) msg;
        System.out.println("接收到:"+in.toString(CharsetUtil.UTF_8));
        ctx.write(in);
    }
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx)throws java.lang.Exception {
        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);//将收到的消息写入发送,不刷新输出消息
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause) throws java.lang.Exception {
        cause.printStackTrace();
        ctx.close();
    }
}
package server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.net.InetSocketAddress;

public class EchoServer {
    private final int port;
    public EchoServer(int port) {
        this.port = port;
    }
    public static void main(String[] args) {
        if(args.length != 1){
            System.err.println("使用:"+EchoServer.class.getSimpleName()+"<Port>");
        }
        int port = Integer.parseInt(args[0]);
        try {
            new EchoServer(port).start();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    private void start() throws InterruptedException {
        final EchoServerHandler serverHandler = new EchoServerHandler();
        NioEventLoopGroup group = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            //配置
            bootstrap.group(group)
                .channel(NioServerSocketChannel.class)
                .localAddress(new InetSocketAddress(port))
                .childHandler(new ChannelInitializer<SocketChannel>(){
                    @Override
                    protected void initChannel(SocketChannel ch)throws java.lang.Exception {
                        ch.pipeline().addLast(serverHandler);//sharable
                    }
                });
            ChannelFuture f = bootstrap.bind().sync();//异步绑定
            f.channel().closeFuture().sync();//阻塞当前线程知道关闭操作
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            group.shutdownGracefully().sync();//释放资源
        }

    }
}
时间: 2024-08-02 06:00:58

java-Netty学习(2)的相关文章

Netty学习5-Netty3.X服务端与客户端

Server1 import java.net.InetSocketAddress; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.ch

Java语言学习的要点

    Java的学习是比较复杂的,主要表现在相关的一系列平台.规范和协议上.有经验的Java程序员都知道,只掌握了Java语言本身很难开发应用程序.本文不讨论这些复杂的概念,而是从初学者的角度,对于Java语言本身的学习提出自己的见解和建议.本文的讨论基于以下假设:? 学习的目的是为了将来进行应用程序的开发,而不是进行语言理论研究? 将来的应用开发是在成熟的平台上展开,而不是自己从底层开发平台掌握静态方法和属性静态方法和属性用于描述某一类对象群体的特征,而不是单个对象的特征.java中大量应用

JAVA/JSP学习系列之八(改写MySQL翻页例子)

js|mysql|翻页 一.前言 其实,改写后的JDBC Data-Source是运行在Servlet中的,通过JNDI去查找数据源.我用Orion试的,将本站<JAVA/JSP学习系列之六(MySQL翻页例子) > 简单改写了一下. 二.配置 (1)JDBC 需要将用到的JDBC驱动Copy到[ORION]/lib目录下 (2)data-source 在[ORION]/config/data-sources.xml文件中加入如下: 〈data-source class="com.e

【Java面向对象学习】一张图搞定Java面向对象

刚开始学习Java的时候,一个人跌跌撞撞摸索着往前走,很多东西理解的也懵懵懂懂,后来实践的多了,才慢慢清楚:许多东西虽然很基础但是却很重要,是需要反复思考和加深理解的,[Java面向对象学习]一张图搞定Java面向对象,分享一些归纳总结后的技术干货,一张图能搞定的事,绝对不长篇大论. 大家都知道,Java面向对象是Java的一个核心,也是初学者的一个难点,所以我们从这里开始,Let's go ! Java面向对象 面向对象(Oriented Object) 是相对于面向过程而言的,过程其实就是函

java系统学习指导与规划

很多同学刚刚学习java,不清楚java应该如何系统学习,今天我就给各位同学做一个java系统学习指导和规划,为大家讲讲如何系统的学习java. 第一:学java首先你要学 J2SE,它是java体系的基础,也是重中之重.很多人往往不重视基础,其实这是舍本逐末的做法.说这么多就是希望大家能重视基础,能在这条路上走的更远. 学j2se有下面几个目标: 1.你要能真正理解面向对象的优势,理解为什么不是面向过程. 2.掌握java语法基础.包括异常处理.多线程.网络编程.GUI编程等 3.如果你对sw

final-Thinking in Java关于学习匿名内部类遇到的问题

问题描述 Thinking in Java关于学习匿名内部类遇到的问题 // An anonymous inner class that performs initialization.//A briefer version of Parcel5.java. public interface Destination{ String readLabel();}public class Parcel9 { // Argument must be final to use inside anonymo

Java自学能学会吗?Java新手学习路线

作为一种灵活多变前景可瞻,又易学习的编程语言--Java备受年轻人关注,很多开发爱好者,或者想从事Java开发的年轻人放出豪言"我要自学Java,拿高薪,走上人生巅峰" 但是:Java自学能学会吗? 就好像一千个人心中有一千个哈利波特一样,这个答案不绝对也不唯一,Java好学但自学的确阻力有些大,作为一门技术语言,它所蕴含的智慧绝对不是靠几本XX入门,XX框架之类的书所能概括,自学Java你要做好一种英语0基础达到4级水平的准备!在这里中软卓越Java培训为大家整理出了一些自学Java

Java 8学习资料汇总

本文首发于InfoQ. Java 8发布已经有一段时间,它被认为是Java 5发布以来最大的一次版本升级.Java 8 为Java语言.编译器.类库.开发工具以及JVM(Java虚拟机)带来了大量新特性.Lambda表达式.默认方法.并行API等都受到了开发者的追捧,社区上关于Java 8的学习资料如雨后春笋般涌现.下面是一些优秀的学习资料汇总: Brian Goetz在Stack Overflow上的回答Brian是<Java并发编程实战>的作者之一,有20多年的软件咨询行业经验.Brian

解决方案-java netty NoClassDefFoundError 找不到eventloop class

问题描述 java netty NoClassDefFoundError 找不到eventloop class 在eclipse上用用netty框架写了个demo,直接在eclipse上能编译运行成功,导出了个jar包, 用java -jar 运行后,报出了如下错误: Error: A JNI error has occurred, please check your installation and try again Exception in thread "main" java.

Java JDBC学习实战(二): 管理结果集

在我的上一篇博客<Java JDBC学习实战(一): JDBC的基本操作>中,简要介绍了jdbc开发的基本流程,并详细介绍了Statement和PreparedStatement的使用:利用这两个API可以执行SQL语句,完成基本的CURD操作.那么,当我们进行查询操作,查询到了结果集,该如何处理呢? Java提供了一个API,专门用于表示查询的结果集--ResultSet.此外,还提供了一个结果集的分析工具--ResultSetMetaData. 一. ResultSet的介绍 1.1 可移