第二章:第一个Netty程序
第一步:设置开发环境
• 安装JDK,下载地址http://www.oracle.com/technetwork/java/javase/archive-139210.html
• 下载netty包,下载地址http://netty.io/
• 安装Eclipse
导入包
第二步:编写一个应答服务器
通过创建ServerBootstrap对象来启动服务器,然后配置这个对象的相关选项,如端口、线程模式、事件循环,并且添加逻辑处理程序用来处理业务逻辑(下面是个简单的应答服务器例子)
- package com.lzh.netty;
- import io.netty.bootstrap.ServerBootstrap;
- import io.netty.channel.ChannelFuture;
- import io.netty.channel.ChannelInitializer;
- import io.netty.channel.ChannelOption;
- import io.netty.channel.EventLoopGroup;
- import io.netty.channel.nio.NioEventLoopGroup;
- import io.netty.channel.socket.SocketChannel;
- import io.netty.channel.socket.nio.NioServerSocketChannel;
- /**
- * 通过创建ServerBootstrap对象来启动服务器,然后配置这个对象的相关选项,如端口、线程模式、事件循环,并且添加逻辑处理程序用来处理业务逻辑
- */
- public class NettyServer {
- private final int port;
- public NettyServer(int port){
- this.port=port;
- }
- public void start() throws Exception{
- //1.第一个线程组是用于接收Client端连接的
- EventLoopGroup bossGroup = new NioEventLoopGroup();
- //2.第二个线程组是用于实际的业务处理的
- EventLoopGroup workerGroup = new NioEventLoopGroup();
- try{
- //创建ServerBootstrap实例来引导绑定和启动服务器
- ServerBootstrap b=new ServerBootstrap();
- //1.设置InetSocketAddress让服务器监听某个端口已等待客户端连接。
- //2.指定NIO的模式,如果是客户端就是NioSocketChannel
- //3.调用childHandler方法传ChannelInitializer类型的参数,ChannelInitializer是个抽象类,所以需要实现initChannel方法,这个方法就是用来设置ChannelHandler
- b.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class)
- .option(ChannelOption.SO_BACKLOG, 1024)//连接数
- .option(ChannelOption.SO_SNDBUF, 32*1024)//设置发送缓冲区
- .option(ChannelOption.SO_RCVBUF, 32*1024)//设置接收缓冲区
- .option(ChannelOption.SO_KEEPALIVE, true)//长连续
- .childHandler(new ChannelInitializer<SocketChannel>() {
- protected void initChannel(SocketChannel cn) throws Exception {
- cn.pipeline().addLast(new NettyServerHandler());
- }
- });
- //绑定服务器等待直到绑定完成,调用sync()方法会阻塞直到服务器完成绑定,然后服务器等待通道关闭,因为使用sync(),所以关闭操作也会被阻塞
- ChannelFuture f=b.bind(port).sync();
- if (f.isSuccess()) {
- System.out.println("启动Netty服务成功,端口号:" + this.port);
- }
- //这里会一直等待,直到socket被关闭
- f.channel().closeFuture().sync();
- }finally{
- //关闭EventLoopGroup和释放所有资源,包括创建的线程
- bossGroup.shutdownGracefully();
- workerGroup.shutdownGracefully();
- }
- }
- public static void main(String[] args) throws Exception{
- new NettyServer(8000).start();
- }
- }
实现服务器业务逻辑
- package com.lzh.netty;
- import io.netty.buffer.ByteBuf;
- import io.netty.buffer.Unpooled;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.channel.ChannelInboundHandlerAdapter;
- public class NettyServerHandler extends ChannelInboundHandlerAdapter{
- //重写channelRead方法,这个方法在任何时候都会被调用来接收数据
- @Override
- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
- ByteBuf buf=(ByteBuf)msg;
- byte [] bt=new byte[buf.readableBytes()];
- buf.readBytes(bt);
- System.out.println("Server received: " + new String(bt,"utf-8"));
- //服务器返回客户端信息
- String str="Hi client !!!";
- ctx.writeAndFlush(Unpooled.copiedBuffer(str.getBytes()));
- }
- //重写ChannelHandler的exceptionCaught方法可以捕获服务器的异常,
- //比如客户端连接服务器后强制关闭,服务器会抛出"客户端主机强制关闭错误",通过重写exceptionCaught方法就可以处理异常
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
- throws Exception {
- cause.printStackTrace();
- ctx.close();
- }
- }
说明:
1.Netty使用多个Channel Handler来达到对事件处理的分离,因为可以很容的添加、更新、删除业务逻辑处理handler。Handler很简单,它的每个方法都可以被重写,它的所有的方法中只有channelRead方法是必须要重写的。
2.重写ChannelHandler的exceptionCaught方法可以捕获服务器的异常,比如客户端连接服务器后强制关闭,服务器会抛出"客户端主机强制关闭错误",通过重写exceptionCaught方法就可以处理异常,比如发生异常后关闭ChannelHandlerContext。
第三步:编写应答程序的客户端
- package com.lzh.netty;
- import io.netty.bootstrap.Bootstrap;
- import io.netty.buffer.Unpooled;
- import io.netty.channel.ChannelFuture;
- import io.netty.channel.ChannelInitializer;
- import io.netty.channel.EventLoopGroup;
- import io.netty.channel.nio.NioEventLoopGroup;
- import io.netty.channel.socket.SocketChannel;
- import io.netty.channel.socket.nio.NioSocketChannel;
- public class NettyClient {
- 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对象并设置到Bootstrap中,EventLoopGroup可以理解为是一个线程池,这个线程池用来处理连接、接受数据、发送数据
- EventLoopGroup group =new NioEventLoopGroup();
- try{
- //创建Bootstrap对象用来引导启动客户端
- Bootstrap b=new Bootstrap();
- // 1.创建InetSocketAddress并设置到Bootstrap中,InetSocketAddress是指定连接的服务器地址
- // 2.添加一个ChannelHandler,客户端成功连接服务器后就会被执行
- b.group(group).channel(NioSocketChannel.class)
- //.remoteAddress(new InetSocketAddress(host,port))
- .handler(new ChannelInitializer<SocketChannel>() {
- @Override
- protected void initChannel(SocketChannel ch) throws Exception {
- //添加一个“入站”handler到ChannelPipeline
- ch.pipeline().addLast(new NettyClientHandler());
- }
- });
- //调用Bootstrap.connect()来连接服务器
- ChannelFuture f=b.connect(host, port).sync();
- f.channel().writeAndFlush(Unpooled.copiedBuffer("hello netty".getBytes()));
- Thread.sleep(1000);
- f.channel().writeAndFlush(Unpooled.copiedBuffer("hello netty1".getBytes()));
- Thread.sleep(1000);
- f.channel().writeAndFlush(Unpooled.copiedBuffer("hello netty2".getBytes()));
- f.channel().closeFuture().sync();
- }finally{
- //关闭EventLoopGroup来释放资源
- group.shutdownGracefully().sync();
- }
- }
- public static void main(String[] args) throws Exception{
- new NettyClient("127.0.0.1", 8000).start();
- }
- }
实现客户端的业务逻辑
- package com.lzh.netty;
- import io.netty.buffer.ByteBuf;
- import io.netty.buffer.ByteBufUtil;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.channel.SimpleChannelInboundHandler;
- public class NettyClientHandler extends SimpleChannelInboundHandler<ByteBuf>{
- @Override
- protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg)throws Exception {
- ByteBuf buf=(ByteBuf)msg;
- byte [] bt=new byte[buf.readableBytes()];
- buf.readBytes(bt);
- System.out.println("Client received: " + new String(bt,"utf-8"));
- System.out.println("Client received: " + ByteBufUtil.hexDump(msg.readBytes(msg.readableBytes())));
- }
- //重写ChannelHandler的exceptionCaught方法可以捕获服务器的异常,
- //比如客户端连接服务器后强制关闭,服务器会抛出"客户端主机强制关闭错误",通过重写exceptionCaught方法就可以处理异常
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
- throws Exception {
- cause.printStackTrace();
- ctx.close();
- }
- /**
- * 1.为什么在这里使用的是SimpleChannelInboundHandler而不使用ChannelInboundHandlerAdapter?
- * 主要原因是ChannelInboundHandlerAdapter在处理完消息后需要负责释放资源。在这里将调用ByteBuf.release()来释放资源。
- * SimpleChannelInboundHandler会在完成channelRead0后释放消息,这是通过Netty处理所有消息的ChannelHandler实现了ReferenceCounted接口达到的。
- * 2.为什么在服务器中不使用SimpleChannelInboundHandler呢?因为服务器要返回相同的消息给客户端,在服务器执行完成写操作之前不能释放调用读取到的消息,因为写操作是异步的,一旦写操作完成后,Netty中会自动释放消息。
- */
- }
第四步:编译和运行服务器和客户端
服务端启动
客户端启动
:
第二章:第一个Netty程序的更多相关文章
- Netty In Action中国版 - 第二章:第一Netty程序
本章介绍 获得Netty4最新的版本号 设置执行环境,以构建和执行netty程序 创建一个基于Netty的server和client 拦截和处理异常 编制和执行Nettyserver和client 本 ...
- Pro ASP.NET MVC –第二章 第一个MVC程序
学习一个软件开发框架的最有效的方式就是了解并使用它.在本章,你将会创建一个简单基于ASP.NET MVC Framework的数据-实体应用程序.我们会该程序划分成若干小块,每次介绍一个部分,以便你能 ...
- Netty(1):第一个netty程序
为什么选择Netty netty是业界最流行的NIO框架之一,它的健壮型,功能,性能,可定制性和可扩展性都是首屈一指的,Hadoop的RPC框架Avro就使用了netty作为底层的通信框架,此外net ...
- Prism 文档 第二章 初始化Prism应用程序
第二章 初始化Prism应用程序 本章将讨论为了使一个Pr ...
- C#语言————第一章 第一个C#程序
第一章 第一个C#程序 ******************C#程序*************** ①:建立项目:文件-->新建-->项目-->c#-->控制台程 ...
- JavaWeb学习总结第二篇--第一个JavaWeb程序
JavaWeb学习总结第二篇—第一个JavaWeb程序 最近我在学院工作室学习并加入到研究生的项目中,在学长学姐的带领下,进入项目实践中,为该项目实现一个框架(用已有框架进行改写).于是我在这里记录下 ...
- C#第一章 第一个C#程序
第一个C#程序 namespace 是C#中组织代码的方式,它的作用那个类似java中的包 using 在Java中作用如果导入其他包 应该是用import关键字而在C#中应使用using关键字来引用 ...
- 从零开始学习Hadoop--第2章 第一个MapReduce程序
1.Hadoop从头说 1.1 Google是一家做搜索的公司 做搜索是技术难度很高的活.首先要存储很多的数据,要把全球的大部分网页都抓下来,可想而知存储量有多大.然后,要能快速检索网页,用户输入几个 ...
- Java面向对象编程 第二章 第一个Java应用
2.1创建Java源文件 Java应用由一个或多个扩展名为".java"的文件构成,这些文件被称为Java源文件,从编译的角度,则被称为编译单元. 本章包含两个Java源文件:Do ...
随机推荐
- R--线性回归诊断(二)
线性回归诊断--R [转载时请注明来源]:http://www.cnblogs.com/runner-ljt/ Ljt 勿忘初心 无畏未来 作为一个初学者,水平有限,欢迎交流指正. R--线性回 ...
- DBUtils学习总结
这几天闲着无聊,就看了一下DBUtils这个数据库组件.中间有了一些想法,现在记录下来. 文章主要分几部分 1 最简单同时也是最经常使用的一些范例 2 学习源码前的一些知识储备 3 我自己写的mydb ...
- 【一天一道LeetCode】#23. Merge k Sorted Lists
一天一道LeetCode系列 (一)题目 Merge k sorted linked lists and return it as one sorted list. Analyze and descr ...
- 如何修改新建脚本模板-ScriptTemplates(Unity3D开发之十五)
猴子原创,欢迎转载.转载请注明: 转载自Cocos2Der-CSDN,谢谢! 原文地址: http://blog.csdn.net/cocos2der/article/details/44957631 ...
- sql的sum函数(与group by,having子句混合使用)
SELECT Customer,SUM(OrderPrice) FROM Orders WHERE Customer='Bush' OR Customer='Adams' GROUP BY Custo ...
- C语言字符串的常见特殊操作(除了string.c实现的那些接口)
字符串操作中,必须掌握的一些之前已经在文章有写过了,比如说字符串查找,字符串粘帖,字符串拷贝等等,这些在标准C库的string.c中已经有实现,故包含#include <string.h> ...
- Hibernate之初体验
在开始学Hibernate之前,一直就有人说:Hibernate并不难,无非是对JDBC进一步封装.一句不难,难道是真的不难还是眼高手低? 如果只是停留在使用的层面上,我相信什么技术都不难,看看别人怎 ...
- Gulp基础知识
首先,我们需要了解Gulp能做些什么? 编译 sass sass是什么?(使CSS可以用编程的方式写,加快我们开发的速度) ...
- js定义数组的方法
1.定义时赋值 var mycars=new Array("a","b","c") 2.new一个数组对象 var mycars=new A ...
- javaScript(1)---概述
javaScript(1)---概述 学习要点: 1.什么是JavaScript 2.JavaScript特点 3.JavaScript历史 4.JavaScript核心 JavaScript诞生于1 ...