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服务器).在文章的最后 ...
随机推荐
- Nginx1.6 for centos6.5安装
Nginx 学习文档:http://www.cnblogs.com/zhoulf/archive/2013/02/09/2909653.html 下载地址:http://nginx.org/en/do ...
- FreeBSD内核之中的一个 ALQ机制的使用
背景: 笔者由于一个项目,这段时间在使用FreeBSD进行内核模块的编程. 之前做过一段时间的Linux下驱动模块编程.对Linux下的模块编程还算熟悉. 如今突然转到FreeBSD下.尽管Linux ...
- poj--1753--Flip Game(dfs好题)
Flip Game Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 37201 Accepted: 16201 Descr ...
- Django day24 cbv和APIView的源码分析 和 resful的规范
一:cbv的源码分析 1.CBV和FBV的区别: - Class Base View CBV(基于类的视图) - Function Base View FBV(基于函数的视图) 2.as_vi ...
- Android框架式编程之Android Architecture Components
1. 当前Android开发面临的问题 Android开发不同于传统的桌面程序开发,桌面程序一般都有唯一的快捷方式入口,并且常作为单进程存在:而一个典型的Android应用通常由多个应用组件构成,包括 ...
- MySQL Connector for .NET 和 EF版本匹配问题
以下讨论的都是EF5.0, 版本号:4.4.0.0 如果装了MySQL 5.0.1 , 那么最好用MySQL Connector 6.3.6,但是创建数据库后,生成迁移历史表的时候,会报错,你不管,直 ...
- Power BI 入门资料
1.官方文档 Power BI Desktop:https://docs.microsoft.com/zh-cn/power-bi/desktop-getting-started Power BI 报 ...
- 【Oracle】设置快速恢复区及reset快速恢复区
快速恢复区 概念 是一个默认放置所有备份恢复操作有关文件的地方,包括:控制文件在线镜像.在线重做日志.归档日志.外来归档日志.控制文件镜像复制.数据文件镜像复制.RMAN备份片和闪回日志. 如果启用的 ...
- C# Datetime 使用详解
获得当前系统时间: DateTime dt = DateTime.Now; Environment.TickCount可以得到“系统启动到现在”的毫秒值 DateTime now = DateTime ...
- ANN:DNN结构演进History—LSTM网络
为了保持文章系列的连贯性,参考这个文章: DNN结构演进History-LSTM_NN 对于LSTM的使用:谷歌语音转录背后的神经网络 摘要: LSTM使用一个控制门控制参数是否进行梯度计算,以此避免 ...