netty helloWord (一)
什么是nettty
netty是基于javaNio模型的网络编程框架。很多框架底层也是用netty实现的 比如dubbo
与NIO的区别
1.简化了API的使用。基于事件驱动。只需要在对应的事件写相应的业务就行了。
2.上层封装多种协议的实现 webSoket,http。同时修复了NIO的bug(内存泄漏 nio buffer构造函数私有无法扩展问题)
Server代码
package com.liqiang.nettyTest2; import java.net.InetSocketAddress;
import java.util.List;
import java.util.Vector; import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
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;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder; public class Server {
private int port;//监听端口
private Vector<ChannelHandlerContext> clients;//保存在线客户端信息
public Server(int port) {
clients=new Vector<ChannelHandlerContext>();
this.port=port;
}
//广播
public void sendAll(String msg) {
clients.forEach(c->{
c.writeAndFlush(msg);
});
}
public void addClient(ChannelHandlerContext client) {
clients.add(client);
}
public void start() {
/**
* NioEventLoopGroup 内部维护一个线程池
* 如果构造函数没有指定线程池数量 则默认为系统core*2
*/
EventLoopGroup acceptor=new NioEventLoopGroup();//acceptor负责监客户端连接请求
EventLoopGroup worker=new NioEventLoopGroup();//worker负责io读写(监听注册channel的 read/writer事件) ServerBootstrap bootstrap=new ServerBootstrap();
bootstrap.group(acceptor,worker)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.childHandler(new ServerChannelInitializer(this)).option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
try {
ChannelFuture channelFuture= bootstrap.bind(port).sync(); System.out.println("服务器已启动");
//将阻塞 直到服务器端关闭或者手动调用
// channelFuture.channel().closeFuture().sync();
//释放资源
//acceptor.shutdownGracefully();
//worker.shutdownGracefully();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} }
ServerChannelInitializer实现
package com.liqiang.nettyTest2; import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder; public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> { private Server server;
public ServerChannelInitializer(Server server) {
this.server=server;
}
@Override
protected void initChannel(SocketChannel channel) throws Exception {
// TODO Auto-generated method stub
channel.pipeline()
.addLast("decoder",new StringDecoder())//接收到数据 自动将将buffer转换为String 避免自己再转
.addLast("encoder",new StringEncoder())//发送数据 可以直接发送String 框架内部转换为buffer传输
.addLast(new ServerHandle(server));
} }
decoder和ecoder都是和ServerHandle间接继承了ChannelInboundHandlerAdapter
表示addLast可以注册多个管道 相当于责任链模式的变种 pipeline注册的Handle都会根据顺序被执行
ServerHandle实现
package com.liqiang.nettyTest2; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter; public class ServerHandle extends ChannelInboundHandlerAdapter { private Server server;
public ServerHandle(Server server) {
// TODO Auto-generated constructor stub
this.server=server;
}
// 建立连接时回调
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// TODO Auto-generated method stub
System.out.println("有客户端建立连接了");
server.addClient(ctx);
//ctx.fireChannelActive();//pipeline可以注册多个handle 这里可以理解为是否通知下一个Handle继续处理
} //接收到客户端发送消息时回调
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// TODO Auto-generated method stub
System.out.println("server接收到客户端发送信息:"+msg.toString());
//ctx.fireChannelRead(msg);pipeline可以注册多个handle 这里可以理解为是否通知下一个Handle继续处理
}
//通信过程中发生异常回调
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// TODO Auto-generated method stub
//super.exceptionCaught(ctx, cause);
ctx.close();//发生异常关闭通信通道
cause.printStackTrace();//打印错误信息
//ctx.fireExceptionCaught(cause);pipeline可以注册多个handle 这里可以理解为是否通知下一个Handle继续处理
}
}
Client端实现
package com.liqiang.nettyTest2; import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
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;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.concurrent.EventExecutorGroup; public class Client {
private String ip;// ip
private int port;// 端口
private boolean isConnection = false;
private ChannelHandlerContext serverChannel;//服务器端的通信通道 public Client(String ip, int port) {
this.ip = ip;
this.port = port;
} // 与服务器建立连接
public void connection() {
EventLoopGroup group = new NioEventLoopGroup();// 服务器监听服务器发送信息
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ClientChannelInitializer(this));
try {
ChannelFuture channelFuture = bootstrap.connect(ip, port).sync();
// System.out.println(channelFuture.isSuccess());
// 监听是否连接成功
while (!isConnection) {
Thread.sleep(1000); } // channelFuture.channel().closeFuture().sync(); 断开连接才会往下执行
} catch (InterruptedException e) {
// TODO Auto-generated catch block
System.out.println("连接服务器失败");
}
} public boolean isConnection() {
return isConnection;
} public void setConnection(boolean isConnection) {
this.isConnection = isConnection;
} public void sendMsg(String msg) {
serverChannel.writeAndFlush(msg);
} public ChannelHandlerContext getServerChannel() {
return serverChannel;
} public void setServerChannel(ChannelHandlerContext serverChannel) {
this.serverChannel = serverChannel;
} }
ClientChannelInitializer
package com.liqiang.nettyTest2; import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder; public class ClientChannelInitializer extends ChannelInitializer<SocketChannel> { private Client client;
public ClientChannelInitializer(Client client) {
// TODO Auto-generated constructor stub
this.client=client;
}
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
// TODO Auto-generated method stub
socketChannel.pipeline()
.addLast("decoder",new StringDecoder())//注册String编码器和解码器 会在发送数据和接收数据通过编码器和解码器转换为String
.addLast("encoder",new StringEncoder())
.addLast(new ClientHandle(client));//注册处理器 }
}
ClientHandle
package com.liqiang.nettyTest2; import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.cors.CorsHandler; public class ClientHandle extends ChannelInboundHandlerAdapter { Client client;
public ClientHandle(Client client) {
// TODO Auto-generated constructor stub
this.client=client;
} //建立连接时回调
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// TODO Auto-generated method stub
//System.out.println("与服务器建立连接成功");
client.setServerChannel(ctx);
client.setConnection(true);
//ctx.fireChannelActive();//如果注册多个handle 下一个handel的事件需要触发需要调用这个方法 }
//读取服务器发送信息时回调
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// TODO Auto-generated method stub
System.out.println(msg.toString());
} //发生异常时回调
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// TODO Auto-generated method stub
cause.printStackTrace();//打印异常
ctx.close();//关闭连接
}
}
测试
package com.liqiang.nettyTest2;
public class nettyMain {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
Server server = new Server(8081);
server.start();
try {
Thread.sleep(5000);//5秒后测试服务器端广播功能
server.sendAll("服务器端广播信息");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
Client client1=new Client("127.0.0.1", 8081);
client1.connection();
client1.sendMsg("我是客户端1");
Client client2=new Client("127.0.0.1", 8082);
client2.connection();
client2.sendMsg("我是客户端2");
}
}).start();
}
}
输出

通过netty可以轻松实现点对点 一对多 广播等功能 但是对于netty的学习不应止与此
netty helloWord (一)的更多相关文章
- netty为啥要二次开发
很早之前就看过李林峰写的netty的书,但是感觉没有直接用到还是理解不够深入,现在的公司有两套自己基于Netty开发的系统,感觉才真正理解为啥要这么做 借用别人文章回顾下 https://www.cn ...
- netty 拆包和粘包 (三)
在tcp编程底层都有拆包和粘包的机制 拆包 当发送数据量过大时数据量会分多次发送 以前面helloWord代码为例 package com.liqiang.nettyTest2; public c ...
- java使用netty模拟实现一个类dubbo的分布式服务调用框架
本文较长,如果想直接看代码可以查看项目源码地址: https://github.com/hetutu5238/rpc-demo.git 要想实现分布式服务调用框架,我们需要了解分布式服务一般需要的功能 ...
- 谈谈如何使用Netty开发实现高性能的RPC服务器
RPC(Remote Procedure Call Protocol)远程过程调用协议,它是一种通过网络,从远程计算机程序上请求服务,而不必了解底层网络技术的协议.说的再直白一点,就是客户端在不必知道 ...
- 基于netty http协议栈的轻量级流程控制组件的实现
今儿个是冬至,所谓“冬大过年”,公司也应景五点钟就放大伙儿回家吃饺子喝羊肉汤了,而我本着极高的职业素养依然坚持留在公司(实则因为没饺子吃没羊肉汤喝,只能呆公司吃食堂……).趁着这一个多小时的时间,想跟 ...
- 从netty-example分析Netty组件续
上文我们从netty-example的Discard服务器端示例分析了netty的组件,今天我们从另一个简单的示例Echo客户端分析一下上个示例中没有出现的netty组件. 1. 服务端的连接处理,读 ...
- 源码分析netty服务器创建过程vs java nio服务器创建
1.Java NIO服务端创建 首先,我们通过一个时序图来看下如何创建一个NIO服务端并启动监听,接收多个客户端的连接,进行消息的异步读写. 示例代码(参考文献[2]): import java.io ...
- 从netty-example分析Netty组件
分析netty从源码开始 准备工作: 1.下载源代码:https://github.com/netty/netty.git 我下载的版本为4.1 2. eclipse导入maven工程. netty提 ...
- Netty实现高性能RPC服务器优化篇之消息序列化
在本人写的前一篇文章中,谈及有关如何利用Netty开发实现,高性能RPC服务器的一些设计思路.设计原理,以及具体的实现方案(具体参见:谈谈如何使用Netty开发实现高性能的RPC服务器).在文章的最后 ...
随机推荐
- 开发DataSnapserver
在上次的文章中讨论了怎样把传统的Delphi 主从架构应用程序逐渐转换为DataSnap JSONserver.在本篇文章中让我们正式讨论怎样使用Delphi XE开发DataSnap/REST ...
- 好记性不如烂笔头——.NET运行原理
WINDOWS中运行的代码,分为托管代码和非托管代码. .NET环境中运行的代码就是托管代码,.NET环境外运行的就是非托管代码. 我们开发的时候,会对源代码进行编译.但其实,对于托管代码,我们编译出 ...
- C++常用字符串分割方法实例汇总
投稿:shichen2014 字体:[增加 减小] 类型:转载 时间:2014-10-08我要评论 这篇文章主要介绍了C++常用字符串分割方法实例汇总,包括了strtok函数.STL.Boost等常用 ...
- poj--1753--Flip Game(dfs好题)
Flip Game Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 37201 Accepted: 16201 Descr ...
- hdu3853LOOPS(概率与期望dp)
LOOPS Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 125536/65536 K (Java/Others)Total Sub ...
- 优先队列 + 并查集 + 字典树 + 欧拉回路 + 树状数组 + 线段树 + 线段树点更新 + KMP +AC自动机 + 扫描线
这里给出基本思想和实现代码 . 优先队列 : 曾经做过的一道例题 坦克大战 struct node { int x,y,step; friend bool operator <(no ...
- HBase编程 API入门系列之get(客户端而言)(2)
心得,写在前面的话,也许,中间会要多次执行,连接超时,多试试就好了. 前面是基础,如下 HBase编程 API入门系列之put(客户端而言)(1) package zhouls.bigdata.Hba ...
- CSS的常用属性(三)
静态定位 position: static (默认) 标准流 绝对定位 position: absolute 特点: 元素使用绝对定位之后,不占据原来的位置(脱标) 元素使用绝对定位,位置是从浏览器出 ...
- 易企CMS仿站标签说明
头部标签: 每个页面都必须加的三大标签(将标签放入header.tpl里面,这样只需在每个模板中调用header.tpl即可): <title>{$seotitle}_{$sitename ...
- dubbo之服务分组
当一个接口有多种实现时,可以用group区分. 服务 <dubbo:service group="feedback" interface="com.xxx.Inde ...