- 浏览: 1238244 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (193)
- ant/maven (6)
- algorithm (5)
- tomcat/weblogic/jboss (6)
- javascript/jquery (13)
- java (33)
- flex/flash (0)
- JPA/Hibernate/myBatis (18)
- java concurrent (7)
- test (2)
- windows/linux (6)
- java collection (7)
- design pattern (2)
- life/health (3)
- database (12)
- IDE (4)
- spring/ejb (20)
- html/css/ckeditor (7)
- jsp/servlet (3)
- java io (13)
- java security (4)
- jni (0)
- svn/git (2)
- english (2)
- java jmx (1)
- xml (1)
- struts/springmvc (9)
- middleware (2)
- cache (1)
- cglib (3)
最新评论
-
jlotusYo:
博主,真感谢。
Java 密码扩展无限制权限策略文件 -
senninha:
这个。。是api说明吧。。
ScheduledExecutorService 源码分析 -
zoutao2008:
请问大文件如何处理?按你这种方式的话,文件超过200M时就会报 ...
hessian系列之二:上传文件 -
lwj1113:
lwj1113 写道谢谢博主这么细致的demo;在系列五中通过 ...
myBatis系列之五:与Spring3集成 -
lwj1113:
谢谢博主这么细致的demo;在系列五中通过testng测试类跑 ...
myBatis系列之五:与Spring3集成
Netty是一款基于Java NIO的框架,能够建立通道、
处理事件、编解码和异常处理等,为上层应用提供了清晰、简洁的开发接口:减少用户的编码和错误,使应用开发者能够把注意力集中在业务逻辑上。
下面以回显功能为例:
一、服务端:
1. 实例化引导类
抽象类为AbstractBootstrap,服务端使用ServerBootstrap:
2. 设置参数
Netty将EventLoopGroup, Channel, Address, Handler以及其它配置都放到了AbstractBootstrap中,统一设置:
a. 设置事件组
Netty是基于事件处理的,EventLoopGroup是接口,实现类有NioEventLoopGroup和OioEventLoopGroup (Old IO即Java IO) 等:
b. 设置通道类型
接口为ServerSocketChannel,实现类有NioServerSocketChannel和OioServerSocketChannel。这里使用NioServerSocketChannel
c. 设置服务启动绑定的地址
传入一个SocketAddress实例,指定端口即可(如8080):
当然,也可以在真正绑定的时候设置:
调用sync()会等待前面的方法执行完毕,后面会有很多这样的写法。
ChannelFuture就是Channel的Future类,可以拿到执行结果。
d. 设置childHandler
实现ChannelInitializer接口的initChannel方法,将处理器(业务逻辑)加到通道管道的末尾:
3. 绑定操作
和Socket的绑定类似,如果地址已经通过localAddress设定,这里就可以调用无参方法:
4. 等待结束
5. 最终
在finally块中关闭事件组以及线程池等资源:
二、回显客户端:
和服务端大体类似。不同的地方:
1'. 设置客户端引导类:
2'. 设置参数:
a'. 设置事件组
一个客户端只有一个通道,一个group就够了:
b'. 设置通道类型
根据使用要求,也可以使用其它类型的客户端通道,如OioSocketChannel:
c'. 设置连接地址:
因为是客户端,需要指定连接的服务端主机和端口:
d'. 设置事件处理类:
注意这里的方法是handler
3'. 连接:
这里是连接,而不是绑定。
如果远程地址没有在remoteAddress中设定,需要在连接时设置:
三、事件处理类
EchoServerHandler,EchoClientHandler都是先往引导程序注册,事件发生时触发相应处理方法:
i. 服务器事件处理类
EchoServerHandler扩展io.netty.channel.ChannelInboundHandlerAdapter类,重写下面三个方法,当然,可以根据需要重写更多的方法:
channelRead: 服务端收到客户端发来的数据
channelReadComplete: 服务端读取客户端数据完毕
exceptionCaught: 发生异常,比如客户端关闭连接时
ii. 客户端事件处理类
EchoClientHandler扩展io.netty.channel.SimpleChannelInboundHandler类,重写下面三个方法:
channelActive: 连接已建立,这时可以向服务端发送数据
channelRead0: 服务端向客户端发送数据,可以读取
exceptionCaught: 发生异常,比如服务端关闭连接时
四、代码
回显服务端
客户端
服务端处理
客户端处理
处理事件、编解码和异常处理等,为上层应用提供了清晰、简洁的开发接口:减少用户的编码和错误,使应用开发者能够把注意力集中在业务逻辑上。
下面以回显功能为例:
一、服务端:
1. 实例化引导类
抽象类为AbstractBootstrap,服务端使用ServerBootstrap:
ServerBootstrap b = new ServerBootstrap();
2. 设置参数
Netty将EventLoopGroup, Channel, Address, Handler以及其它配置都放到了AbstractBootstrap中,统一设置:
a. 设置事件组
Netty是基于事件处理的,EventLoopGroup是接口,实现类有NioEventLoopGroup和OioEventLoopGroup (Old IO即Java IO) 等:
EventLoopGroup bossGroup = new NioEventLoopGroup(); // 接受连接事件组 EventLoopGroup workerGroup = new NioEventLoopGroup(); // 处理每个连接业务事件组 b.group(bossGroup, workerGroup); // 可以只使用一个group,分成两个group的好处是:业务耗时较长导致阻塞时,不会对接受连接造成影响。
b. 设置通道类型
接口为ServerSocketChannel,实现类有NioServerSocketChannel和OioServerSocketChannel。这里使用NioServerSocketChannel
b.channel(NioServerSocketChannel.class);
c. 设置服务启动绑定的地址
传入一个SocketAddress实例,指定端口即可(如8080):
b.localAddress(new InetSocketAddress(8080))
当然,也可以在真正绑定的时候设置:
ChannelFuture f = b.bind(new InetSocketAddress(8080)).sync();
调用sync()会等待前面的方法执行完毕,后面会有很多这样的写法。
ChannelFuture就是Channel的Future类,可以拿到执行结果。
d. 设置childHandler
实现ChannelInitializer接口的initChannel方法,将处理器(业务逻辑)加到通道管道的末尾:
b.childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new EchoServerHandler()); } });
3. 绑定操作
和Socket的绑定类似,如果地址已经通过localAddress设定,这里就可以调用无参方法:
ChannelFuture f = b.bind().sync();
4. 等待结束
f.channel().closeFuture().sync();
5. 最终
在finally块中关闭事件组以及线程池等资源:
group.shutdownGracefully().sync();
二、回显客户端:
和服务端大体类似。不同的地方:
1'. 设置客户端引导类:
Bootstrap b = new Bootstrap();
2'. 设置参数:
a'. 设置事件组
一个客户端只有一个通道,一个group就够了:
EventLoopGroup group = new NioEventLoopGroup(); b.group(group);
b'. 设置通道类型
根据使用要求,也可以使用其它类型的客户端通道,如OioSocketChannel:
b.channel(NioSocketChannel.class);
c'. 设置连接地址:
因为是客户端,需要指定连接的服务端主机和端口:
b.remoteAddress(new InetSocketAddress(host, port));
d'. 设置事件处理类:
注意这里的方法是handler
b.handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new EchoClientHandler()); } });
3'. 连接:
这里是连接,而不是绑定。
ChannelFuture f = b.connect().sync();
如果远程地址没有在remoteAddress中设定,需要在连接时设置:
ChannelFuture f = b.connect("localhost", 8080);
三、事件处理类
EchoServerHandler,EchoClientHandler都是先往引导程序注册,事件发生时触发相应处理方法:
i. 服务器事件处理类
EchoServerHandler扩展io.netty.channel.ChannelInboundHandlerAdapter类,重写下面三个方法,当然,可以根据需要重写更多的方法:
channelRead: 服务端收到客户端发来的数据
channelReadComplete: 服务端读取客户端数据完毕
exceptionCaught: 发生异常,比如客户端关闭连接时
ii. 客户端事件处理类
EchoClientHandler扩展io.netty.channel.SimpleChannelInboundHandler类,重写下面三个方法:
channelActive: 连接已建立,这时可以向服务端发送数据
channelRead0: 服务端向客户端发送数据,可以读取
exceptionCaught: 发生异常,比如服务端关闭连接时
四、代码
回显服务端
public class EchoServer { private final int port; // 服务端绑定端口 public EchoServer(int port) { this.port = port; } public void start() throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); // 接受连接事件组 EventLoopGroup workerGroup = new NioEventLoopGroup(); // 每个连接业务处理事件组 try { ServerBootstrap b = new ServerBootstrap(); // 引导器 // 指定事件组,通道、绑定地址、业务处理器 b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) .localAddress(new InetSocketAddress(port)).childHandler(new ChannelInitializer<SocketChannel>() { // 虽然EchoServerHandler和ChannelInitializer都是ChannelHandler的实现类,但这里不能直接传入EchoServerHandler,否则会导致业务处理器无法使用 @Override protected void initChannel(SocketChannel ch) throws Exception { // 将业务处理器加到通道管理线(处理器队列)的末尾 ch.pipeline().addLast(new EchoServerHandler()); } }); ChannelFuture f = b.bind().sync(); // 绑定指定端口 System.out.println(EchoServer.class.getName() + " started and listen on " + f.channel().localAddress()); f.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully().sync(); // 释放资源和线程池 } } public static void main(String[] args) throws Exception { args = new String[1]; args[0] = "8180"; if (args.length != 1) { System.err.println("?Usage: ?" + EchoServer.class.getSimpleName() + "<port>?"); } int port = Integer.parseInt(args[0]); new EchoServer(port).start(); } }
客户端
public class EchoClient { private final String host; // 服务器地址 private final int port; // 服务器端口 public EchoClient(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<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new EchoClientHandler()); } }); // 连接到服务端,sync()阻塞直到连接过程结束 ChannelFuture f = b.connect().sync(); // 等待通道关闭 f.channel().closeFuture().sync(); } finally { // 关闭引导器并释放资源,包括线程池 group.shutdownGracefully().sync(); } } public static void main(String[] args) throws Exception { args = new String[2]; args[0] = "mysit.cnsuning.com"; args[1] = "8180"; if (args.length != 2) { System.err.println("Usage: " + EchoClient.class.getSimpleName() + " <host> <port>"); return; } final String host = args[0]; final int port = Integer.parseInt(args[1]); new EchoClient(host, port).start(); } }
服务端处理
public class EchoServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf buf = (ByteBuf) msg; System.out.println("Server received: " + ByteBufUtil.hexDump(buf.readBytes(buf.readableBytes()))); 缓冲内部存储读写位置,readBytes将指针后移 // System.out.println("?Server received: ?" + msg); buf.resetReaderIndex(); // 重置读写位置,如果省略这一句,ctx.write(msg)往客户端发送的数据为空 ctx.write(msg); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { // 读写完毕,调用flush将数据真正发送到客户端 ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); // 打印异常 ctx.close(); // 关闭通道 } }
客户端处理
@Sharable public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { // 连接建立,向服务端发送数据 ctx.write(Unpooled.copiedBuffer("Hello Netty!", CharsetUtil.UTF_8)); // 注意:需要调用flush将数据发送到服务端 ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { // 打印异常并关闭通道 cause.printStackTrace(); ctx.close(); } @Override protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { // 读取服务端返回的数据并打印 System.out.println("Client received: " + ByteBufUtil.hexDump(msg.readBytes(msg.readableBytes()))); } }
发表评论
-
ByteBuffer 源码分析
2014-04-14 11:32 01. duplicate() 创建一个新的ByteBuffe ... -
PushbackInputStream 源码分析
2014-04-19 12:04 1317扩展java.io.FilterInputStream,代表的 ... -
RandomAccessFile 源码分析
2012-11-08 22:12 0public RandomAccessFile(S ... -
Java IO 总结
2013-01-17 17:05 16931. Java的IO运用了装饰者模式,提供了一个称做链接(Ch ... -
FileWriter 源码分析
2012-08-04 12:07 0public class FileWriter exten ... -
StringReader 源码分析
2012-07-12 18:00 1308public class StringReader ext ... -
OutputStreamWriter 源码分析
2012-06-29 09:59 2530字符流通向字节流的桥梁:可使用指定的charset将要写入流中 ... -
InputStreamReader 源码分析
2012-06-28 14:54 2202InputStreamReader在字节流和字符流之间架起了桥 ... -
Writer 源码分析
2012-06-28 17:47 1186Writer是写入字符流的抽象类。子类必须实现的方法有 wri ... -
PrintWriter 源码分析
2012-06-21 09:55 0public class PrintWriter exte ... -
FilterOutputStream 源码分析
2012-05-31 09:54 0public class FilterOutputStr ... -
PipedInputStream 源码分析
2012-05-31 09:53 0public class PipedInputStrea ... -
InputStream的mark和reset方法测试
2012-05-31 09:43 7921public class InputStreamTest ... -
BufferedOutputStream 源码分析
2012-05-30 18:25 5202BufferedOutputStream实现了一个缓冲输出流。 ... -
Reader 源码分析
2012-05-30 15:53 1526读取字符流的抽象类。子类需要重写read(char[], ... -
InputStream 源码分析
2012-05-30 14:38 3588InputStream是所有输入字节流类的超类。所有Input ... -
FileChannel 源码解析
2012-05-29 15:41 0public abstract class FileCh ... -
FileInputStream 源码分析
2012-05-29 10:53 5157java.io.FileInputStream是从文件系统中获 ... -
File 类源代码解析
2013-10-12 17:01 58171. 分隔符 // 名称分隔符,Windows系 ...
相关推荐
通过netty编写文件传输的客户端与服务端,以及协议说明, 通用的netty传输协议 通过该协议进行文件传输 文件传输客户端与服务端 可以根据文件的最后更新时间来增量传输文件 源码开放,通过eclipse或者idea导入代码...
java应用netty服务端和客户端示例,客户端和服务端的model对象目录必须一致
《Netty进阶之路:跟着案例学Netty》中的案例涵盖了Netty的启动和停止、内存、并发多线程、性能、可靠性、安全等方面,囊括了Netty绝大多数常用的功能及容易让人犯错的地方。在案例的分析过程中,还穿插讲解了Netty...
实现Java服务端和C#客户端联通 Java使用Netty 开发环境为IDEA C#使用DotNetty 开发环境为VS2017 运行时先开启Java服务端 再开启客户端
Netty中使用WebSocket实现服务端与客户端的长连接通信发送消息示例代码;Netty中使用WebSocket实现服务端与客户端的长连接通信发送消息示例代码;Netty中使用WebSocket实现服务端与客户端的长连接通信发送消息示例代码
Netty 入门与实战:仿写微信 IM 即时通讯系统
Netty 入门与实战:仿写微信 IM 即时通讯系统,掘金小册子,netty教程。章节齐全无缺失,排版非常不错。 1.仿微信IM系统简介 1 2.Netty是什么? 2 3.服务端启动流程 8 4.客户端启动流程 11 5.实战:客户端与服务端双向...
spring boot 整合的netty 实现的socket的demo(包括服务端和客户端是分开的两个项目,导入idea,启动即可)。
springboot整合netty,分客户端和服务端两个项目,springboot整合netty,分客户端和服务端两个项目,springboot整合netty,分客户端和服务端两个项目,springboot整合netty,分客户端和服务端两个项目
Netty 入门与实战:仿写微信 IM 即时通讯系统
nettyproject NIO编程 基于netty通信框架的服务端,客户端编程 源码阅读。 netty服务端。 网友客户端1118
客户端发送16进制给服务端,并行实现socket通道活动状态和断开重新连接的功能, 监听接口是否存在数据,如果存在socket客户端发送给socket服务端的实现 随着物联网的发展,随之出现了各种传感器监测数据的实时发送,...
利用idea,构建的maven项目,用idea打开即可测试运行,实现了netty的服务段和客户端,利用netty实现服务端和客户端的通信demo.
Java进阶技术-netty进阶之路
用Netty5写一个简单的服务端和客户端,通过这个示例可以起到快速入门的效果,下载完成后,可运行4_Netty5_Hello模块代码,其中包括客户端单连接和多连接的例子
Netty实现简单的客户端服务端通信示例,户端发送请求给服务端,并由服务端响应客户端请求,希望对初学Netty的同学有所帮助。
Android Studio 开发Netty网络访问框架,实现了客户端、服务端两种访问方式,支持发送心跳数据,使用Handler实现外部数据交互,有调用Demo,在实际项目中使用暂时没有问题
Netty 入门与实战:仿写微信 IM 即时通讯系统