什么是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 (一)的更多相关文章

  1. netty为啥要二次开发

    很早之前就看过李林峰写的netty的书,但是感觉没有直接用到还是理解不够深入,现在的公司有两套自己基于Netty开发的系统,感觉才真正理解为啥要这么做 借用别人文章回顾下 https://www.cn ...

  2. netty 拆包和粘包 (三)

    在tcp编程底层都有拆包和粘包的机制   拆包 当发送数据量过大时数据量会分多次发送 以前面helloWord代码为例 package com.liqiang.nettyTest2; public c ...

  3. java使用netty模拟实现一个类dubbo的分布式服务调用框架

    本文较长,如果想直接看代码可以查看项目源码地址: https://github.com/hetutu5238/rpc-demo.git 要想实现分布式服务调用框架,我们需要了解分布式服务一般需要的功能 ...

  4. 谈谈如何使用Netty开发实现高性能的RPC服务器

    RPC(Remote Procedure Call Protocol)远程过程调用协议,它是一种通过网络,从远程计算机程序上请求服务,而不必了解底层网络技术的协议.说的再直白一点,就是客户端在不必知道 ...

  5. 基于netty http协议栈的轻量级流程控制组件的实现

    今儿个是冬至,所谓“冬大过年”,公司也应景五点钟就放大伙儿回家吃饺子喝羊肉汤了,而我本着极高的职业素养依然坚持留在公司(实则因为没饺子吃没羊肉汤喝,只能呆公司吃食堂……).趁着这一个多小时的时间,想跟 ...

  6. 从netty-example分析Netty组件续

    上文我们从netty-example的Discard服务器端示例分析了netty的组件,今天我们从另一个简单的示例Echo客户端分析一下上个示例中没有出现的netty组件. 1. 服务端的连接处理,读 ...

  7. 源码分析netty服务器创建过程vs java nio服务器创建

    1.Java NIO服务端创建 首先,我们通过一个时序图来看下如何创建一个NIO服务端并启动监听,接收多个客户端的连接,进行消息的异步读写. 示例代码(参考文献[2]): import java.io ...

  8. 从netty-example分析Netty组件

    分析netty从源码开始 准备工作: 1.下载源代码:https://github.com/netty/netty.git 我下载的版本为4.1 2. eclipse导入maven工程. netty提 ...

  9. Netty实现高性能RPC服务器优化篇之消息序列化

    在本人写的前一篇文章中,谈及有关如何利用Netty开发实现,高性能RPC服务器的一些设计思路.设计原理,以及具体的实现方案(具体参见:谈谈如何使用Netty开发实现高性能的RPC服务器).在文章的最后 ...

随机推荐

  1. nyoj860 又见01背包(背包变形)

    题目860 pid=860" style="text-decoration:none; color:rgb(55,119,188)">题目信息 执行结果 本题排行 ...

  2. luogu1197 [JSOI2008]星球大战

    题目大意 有一个无向图,每次删除一个节点,求删除后图中连通块的个数.(如果两个星球可以通过现存的以太通道直接或间接地连通,则这两个星球在同一个连通块中) 题解 连通块?用并查集可以找到一个连通块,但是 ...

  3. oc35--自定义构造方法

    // // Person.h #import <Foundation/Foundation.h> @interface Person : NSObject @property int ag ...

  4. 背包问题的方案总数 P1474 货币系统

    背包问题的方案总数 对于一个给定了背包容量.物品费用.物品间相互关系(分组.依赖等)的背包问题,除了再给定每个物品的价值后求可得到的最大价值外,还可以得到装满背包或将背包装至某一指定容量的方案总数. ...

  5. 我在Suse 11 Sp3上使用anaconda安装TensorFlow的过程记录

    我在Suse 11 Sp3上使用anaconda安装TensorFlow的过程记录 准备安装包: gcc48 glibc--SP4-DVD-x86_64-GM-DVD1.iso tensorflow_ ...

  6. [Spring] Spring Boot 生态

  7. PCB Genesis原点坐标转换关系

    一.Genesis原点坐标转换关系: 1.读取Genesis坐标转换:   UI界面坐标 = 文件坐标 - 偏移值 2.写入Genesis坐标转换:   文件坐标 = UI界面坐标 + 偏移值 3.为 ...

  8. A - High School: Become Human

    Problem description Year 2118. Androids are in mass production for decades now, and they do all the ...

  9. 最近积累的JS 东西,分享一下

    js 关闭页面 var browserName=navigator.appName; if (browserName=="Netscape") { window.open('',' ...

  10. 关于改变安卓Button样式,这里有一个好方法。

    首先,在drawable下创建一个新的xml文件(例如我创建的为button.xml).然后在里面输入以下代码. <item> <shape> <gradient and ...