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服务器).在文章的最后 ...
随机推荐
- 弹出框中选项卡的运用(easyUI)
先看一下页面效果: 此处有两个知识点:一个是弹出框的运用,一个是选项卡的运用 分析一下该HTML代码,最外面一个div是弹出框的,默认是关闭状态,可通过ID来控制弹出框的开关,该div的样式是easy ...
- android SearchView 样式修改
try { Class<?> argClass=mSearchView.getClass(); //指定某个私有属性 Field mSearchHintIconField = argCla ...
- Git Stash方法
命令:git stash1.使用git stash 保存当前的工作现场, 那么就可以切换到其他分支进行工作,或者在当前分支上完成其他紧急的工作,比如修订一个bug测试提交. 2.如果一个使用了一个gi ...
- Linux:命令gedit
首先,gedit是一个GNOME桌面环境下兼容UTF-8的文本编辑器.它使用GTK+编写而成,因此它十分的简单易用,有良好的语法高亮,对中文支持很好,支持包括gb2312.gbk在内的多种字符编码. ...
- hdu 1532 Drainage Ditches(最大流)
Drainage Dit ...
- 杂项:MIS(管理信息系统)
ylbtech-杂项:MIS(管理信息系统) 管理信息系统(Management Information System,简称MIS)是一个以人为主导,利用计算机硬件.软件.网络通信设备以及其他办公设备 ...
- 删除项目中的版本控制(SVN)
使用svn进行版本控制,每个文件夹下都有.svn文件夹,有些项目在脱离svn版本控制之后,想删除项目中所有的.svn文件夹,可用下面的方法进行快速删除: 建立一个文本文件,取名为kill-svn-fo ...
- bzoj1030 文本生成器(AC自动机+dp)
1030: [JSOI2007]文本生成器 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 4777 Solved: 1986[Submit][Stat ...
- kafka与zookeeper实战笔记
kafka命令 1.先启动zookeeper zkServer.cmd/zkServer.sh2.启动kafka[需要指定server.properties文件] kafka-server-start ...
- Hadoop一主一从部署(2)
Hadoop部署一主一从(2) 1.关闭防火墙和Linux守护进程 执行命令: iptables -F setenforce 0 2.对Hadoop集群进行初始化,在namenode(主机)上执行命令 ...