一、 Netty介绍

1.什么是netty?
首先我们来看一下官方的介绍:

*Netty is a NIO client server framework which enables quick and easy
development of network applications such as protocol servers and clients. It
greatly simplifies and streamlines network programming such as TCP and UDP
socket server.
‘Quick and easy’ doesn’t mean that a resulting application will suffer from a
maintainability or a performance issue. Netty has been designed carefully with
the experiences earned from the implementation of a lot of protocols such as
FTP, SMTP, HTTP, and various binary and text-based legacy protocols. As a
result, Netty has succeeded to find a way to achieve ease of development,
performance, stability, and flexibility without a compromise.*


Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。
也就是说,Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty
可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。
“快速”和“简单”并不用产生维护性或性能上的问题。Netty
是一个吸收了多种协议的实现经验,这些协议包括FTP,SMTP,HTTP,各种二进制,文本协议,并经过相当精心设计的项目,最终,Netty
成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和伸缩性。

2.netty的应用

1、分布式进程通信
例如: hadoop、dubbo、akka等具有分布式功能的框架,底层RPC通信都是基于netty实现的,这些框架使用的版本通常都还在用netty3.x。

2、游戏服务器开发
最新的游戏服务器有部分公司可能已经开始采用netty4.x 或 netty5.x。

二、netty服务器以及客户端的编写

netty版本大致版本分为 netty3.x 和 netty4.x、netty5.x。这里我们使用netty3.x版本。需要下载相应的jar包导入项目。

首先我们来编写服务器:

Server.java:
package cn.shinelon.server; 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.channel.ChannelPipelineFactory; import
org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.nio
.NioServerSocketChannelFactory; import org.jboss.netty.handler.codec.string
.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; /**
* netty官方文档:http://netty.io/3.10/api/index.html * 服务器 * @author Shinelon * */
public class Server { public static void main(String[] args) { //服务类
ServerBootstrap bootStrap=new ServerBootstrap(); //创建两个线程池 ExecutorService
boss=Executors.newCachedThreadPool(); //线程池中的线程是client,主要负责端口的监听
ExecutorService worker=Executors.newCachedThreadPool(); //主要负责读写任务
//设置niosocket工厂 bootStrap.setFactory(new NioServerSocketChannelFactory(boss,
worker)); //设置管道的工厂 bootStrap.setPipelineFactory(new ChannelPipelineFactory() {
@Override public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline=Channels.pipeline(); //解码 pipeline.addLast("decoder",
new StringDecoder()); //编码 pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("helloHandler", new HelloHandler()); return pipeline; } });
bootStrap.bind(new InetSocketAddress(10101)); System.out.println("Server
Start!!!"); } }
HelloHandler.java:
package cn.shinelon.server; import
org.jboss.netty.channel.ChannelHandlerContext;import
org.jboss.netty.channel.ChannelStateEvent;import
org.jboss.netty.channel.ExceptionEvent;import
org.jboss.netty.channel.MessageEvent;import
org.jboss.netty.channel.SimpleChannelHandler;public class HelloHandler extends
SimpleChannelHandler { /** * channel关闭的时候触发 */ @Override public void
channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception
{ System.out.println("channelClosed"); super.channelClosed(ctx, e); } @Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
throws Exception { System.out.println("channelConnected"); super
.channelConnected(ctx, e); }/** * 必须是链接已经建立,关闭通道的时候会触发 */ @Override public void
channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws
Exception { System.out.println("channelDisconnected"); super
.channelDisconnected(ctx, e); }@Override public void exceptionCaught
(ChannelHandlerContext ctx, ExceptionEvent e)throws Exception {
System.out.println("exceptionCaught"); super.exceptionCaught(ctx, e); } /** *
接收消息 */ @Override public void messageReceived(ChannelHandlerContext ctx,
MessageEvent e)throws Exception { String str=(String) e.getMessage();
System.out.println(str);super.messageReceived(ctx, e); //回写数据
ctx.getChannel().write("hi"); } }
上面代码不难,这里需要说明的是ChannelHandler类,我们重写了它的几个方法:


channelConnected:建立新连接,我们通常可以用来检测IP是否是黑名单,比如有人恶意攻击服务器,我们在连接时可以监听发送来的请求,如果请求过于频繁和流量太大就可以将这个IP加入黑名单。

channelDisconnected:链接关闭,可以再用户断线的时候清楚用户的缓存数据等。

messageReceived:接收消息。

接着我们来编写客户端程序:

Client.java:
package cn.shinelon.client; import java.net.InetSocketAddress; import java.util
.Scanner; import java.util.concurrent.ExecutorService; import java.util
.concurrent.Executors; import org.jboss.netty.bootstrap.ClientBootstrap; import
org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel
.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org
.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss
.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec
.string.StringEncoder; public class Client { public static void main(String[]
args) throws InterruptedException { //服务类 ClientBootstrap bootStrap=new
ClientBootstrap(); //创建两个线程池 ExecutorService boss=Executors.newCachedThreadPool
(); ExecutorService worker=Executors.newCachedThreadPool(); //设置socket工厂
bootStrap.setFactory(new NioClientSocketChannelFactory(boss, worker)); //设置管道工厂
bootStrap.setPipelineFactory(new ChannelPipelineFactory() { @Override public
ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipe=Channels
.pipeline(); pipe.addLast("decoder", new StringDecoder()); pipe.addLast(
"encoder",new StringEncoder()); pipe.addLast("hiHandler", new HiHandler());
return pipe; } }); //连接服务器 ChannelFuture connect=bootStrap.connect(new
InetSocketAddress("127.0.0.1", 10101)); Channel channel=connect.getChannel();
System.out.println("Client Start!!!"); //向服务器发送消息 Scanner scanner=new
Scanner(System.in); while(true) { Thread.sleep(500); System.out.println(
"请输入发送的消息:"); channel.write(scanner.next()); } } }
HiHandler.java:
package cn.shinelon.client; import org.jboss.netty.buffer.ChannelBuffer; import
org.jboss.netty.buffer.ChannelBuffers;import
org.jboss.netty.channel.ChannelHandlerContext;import
org.jboss.netty.channel.ChannelStateEvent;import
org.jboss.netty.channel.ExceptionEvent;import
org.jboss.netty.channel.MessageEvent;import
org.jboss.netty.channel.SimpleChannelHandler;public class HiHandler extends
SimpleChannelHandler { /** * channel关闭的时候触发 */ @Override public void
channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception
{ System.out.println("channelClosed"); super.channelClosed(ctx, e); } @Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
throws Exception { System.out.println("channelConnected"); super
.channelConnected(ctx, e); }/** * 必须是链接已经建立,关闭通道的时候会触发 */ @Override public void
channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws
Exception { System.out.println("channelDisconnected"); super
.channelDisconnected(ctx, e); }@Override public void exceptionCaught
(ChannelHandlerContext ctx, ExceptionEvent e)throws Exception {
System.out.println("exceptionCaught"); super.exceptionCaught(ctx, e); } /** *
接收消息 */ @Override public void messageReceived(ChannelHandlerContext ctx,
MessageEvent e)throws Exception { String str=(String) e.getMessage();
System.out.println(str);super.messageReceived(ctx, e); } }

注意上面的HiHandler和HelloHandler是一样的,只是修改了一下类名而已。至此,我们已经完成了服务器与客户端的编写,下面我们可以进行测试,当客户端向服务器发送消息后,服务器会向客户端回应“hi”的字符串:




友情链接
ioDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信