Netty简单应用
来源:互联网 发布:淘宝店铺规划方案 编辑:程序博客网 时间:2024/05/25 19:56
netty是目前最好的nio框架,一般用来做数据通信.为什么用netty?因为nio编程太麻烦,netty做了很好的封装,是操作更简单,下面我写一个简单的netty框架的应用
首先要使用netty必须引入netty的包,pom文件加入如下代码段
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>5.0.0.Alpha2</version></dependency>
先看服务端
package com.kevindai.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;public class Server { private int port; public Server(int port){ this.port = port; } public void run() throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup();//用于接收进来客户端的连接 EventLoopGroup workerGroup = new NioEventLoopGroup();//用于处理已经被接收的连接 try { ServerBootstrap b = new ServerBootstrap();//启动NIO服务的辅助启动类 b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new ServerHandler());//以上及以下很多都是模板化的代码,主要要更改的是ServerHandler()的实现 } }) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); ChannelFuture f = b.bind(port).sync(); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new Server(port).run(); }}
然后看看服务端的处理类,从客户端接受的数据如何处理都在这里定义,在实际工作中要做修改的一般也是这个地方
package com.kevindai.netty;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelFutureListener;import io.netty.channel.ChannelHandlerAdapter;import io.netty.channel.ChannelHandlerContext;public class ServerHandler extends ChannelHandlerAdapter{ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception{ //获得接收客户端的数据并进行处理 ByteBuf buf = (ByteBuf)msg; byte[] data = new byte[buf.readableBytes()]; buf.readBytes(data); String str = new String(data,"UTF-8"); System.out.println("server get:" + str); //回写给客户端数据 ctx.write(Unpooled.copiedBuffer("msg handled".getBytes())) .addListener(ChannelFutureListener.CLOSE);//发送完数据之后关闭跟客户端的连接 ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4) cause.printStackTrace(); ctx.close(); }}
下面看看客户端如何启动
package com.kevindai.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.ChannelOption;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 Client { public static void main(String[] args) throws Exception { String host = "localhost"; int port = 8080; EventLoopGroup workerGroup = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(workerGroup); b.channel(NioSocketChannel.class); b.option(ChannelOption.SO_KEEPALIVE, true); b.handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new ClientHandler());//客户端接受服务端发送的数据进行的处理逻辑 } }); ChannelFuture f = b.connect(host, port).sync(); f.channel().write(Unpooled.copiedBuffer("test".getBytes()));//发送给服务端数据 f.channel().flush();//发送之后清空缓存 //f.channel().writeAndFlush(Unpooled.copiedBuffer("test".getBytes()));//这行代码和上面两行意思是一样的 f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); } }}
看看客户端处理数据的逻辑,这里的逻辑都很简单,实际情况实际处理
package com.kevindai.netty;import io.netty.buffer.ByteBuf;import io.netty.channel.ChannelHandlerAdapter;import io.netty.channel.ChannelHandlerContext;import io.netty.util.ReferenceCountUtil;public class ClientHandler extends ChannelHandlerAdapter{ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { try { //接收从服务端发送的数据 ByteBuf buf = (ByteBuf)msg; byte[] data = new byte[buf.readableBytes()]; buf.readBytes(data); String request = new String(data, "utf-8"); System.out.println("Client get: " + request); } finally { ReferenceCountUtil.release(msg); } }// @Override// public void channelActive(final ChannelHandlerContext ctx) { // (1)// final ByteBuf time = ctx.alloc().buffer(4); // (2)// time.writeInt((int) (System.currentTimeMillis() / 1000L + 2208988800L));// final ChannelFuture f = ctx.writeAndFlush(time); // (3)// f.addListener(new ChannelFutureListener() {// @Override// public void operationComplete(ChannelFuture future) {// assert f == future;// ctx.close();// }// }); // (4)// } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); }}
1、在实际项目中客户端和服务器端都不在一台服务器中,那么如何如何启动呢?第一种办法是让程序集成在web容器中,比如tomcat,在web容器启动时即启动.第二种办法打成Jar包来运行(这两种办法我这里都不做介绍了)
2、这里存在一个tcp 黏包、拆包的问题,一般有三种解决方案
- 消息定长,例如每个报文的大小固定为一定长度,如果不够就补空格;如果过长会被截取(不推荐)
- 在包尾部增加特殊字符进行分割(推荐,一般通过DelimiterBasedFrameDecoder自定义分隔符实现)
- 将消息分为消息头和消息体,在消息头中包含表示消息总长度的字段,然后再进行业务逻辑处理.(类似自定义协议,比较麻烦,我没试过)
用特殊字符分割的应用如下,跟上面代码最大的区别是服务端加了以下两行
客户端发送信息格式如下
0 0
- Netty简单应用
- netty应用
- zookeeper注册服务与netty的简单结合应用
- spring boot+netty开发简单IM应用(一)
- netty(七)netty入门应用
- Netty入门应用
- 开发Netty应用
- Netty复杂应用
- Pigeon中的Netty应用
- Netty入门应用
- Netty入门应用一
- Netty入门应用
- Netty入门应用开发
- Netty应用篇
- Netty应用篇
- netty简单实例
- netty简单样例
- netty 简单httpserver实现
- Hibernate基础:快速入门(3):SessionFactory和Session
- 利用OpenCV求取图像多轮廓质心,并在输出图像上显示质心坐标
- Long Long 的使用
- MaterialDesign的学习
- MAC查看端口占用情况
- Netty简单应用
- 域名、主机和网站之间的区别
- JVM类加载机制详解(二)类加载器与双亲委派模型
- Ubuntu 安装 JDK 7 / JDK8 的两种方式
- 第十六周--项目2-大数据集上排序算法性能的体验
- (17)方阵的特征值与特征向量
- 使用UltraISO制作U盘启动盘
- 打印菱形星号组合
- Java实现文本、图片、视频的拷贝(从一个地方拷贝到另一个地方)