什么是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. WPF学习笔记——没有前途的WPF

    看上去,WPF比silverlight有前途一点.毕竟,微软还没有宣布,WPF停止更新. 但我怀疑,不久的将来,WPF也会步其子集silverlight的后尘,要么不再出后续版本,要么向HTML5 + ...

  2. 0505 php-数组、控制语句、函数

    数 组 (定义.使用.赋值.遍历.分类.冒泡排序) 1.数组包括元素.下标.数组长度 2.php中的数组长度用$len = count("$数组名"); 3.定义一个数组:$arr ...

  3. 【BZOJ3456】城市规划

    题目 转送门 思路&算法 我们设点数为\(n\)的简单图的数量为\(f_n\), 点数为\(n\)的简单连通图有\(g_i\)个 于是我们知道,从\(n\)个点中选\(2\)个点有\(n \c ...

  4. Python 38 sql基础

    数据库服务器中存放的是 库(文件加)  .表(文件) .表里面是记录(一行数据) 增     删     改     查 1.库相关 创建------------------create databa ...

  5. 语法错误1:TabError: Inconsistent use of tabs and spaces in indentation

    如图错误: 出错原因: 由于写代码过程用的tab缩进 解决方法: 把tab缩进改用空格缩进

  6. BZOJ 3876 有上下界的网络流

    思路: 套用有上下界的网络流 就好了   (这算是裸题吧) 比如 有条 x->y 的边  流量上限为R 下限为L 那么du[x]-=L,du[y]+=L 流量上限变成R-L du[x]>0 ...

  7. A - Supermarket

    Problem description We often go to supermarkets to buy some fruits or vegetables, and on the tag the ...

  8. POI合并单元边框问题解决方法

    http://blog.csdn.net/hardworking0323/article/details/51105430

  9. 软件架构自学笔记——常见的软件架构(https://jiajunhuang.com/articles/2018_09_16-common_software_archtecture_pattern.md.html)

    分层模式 这种模式主要是将设计分层,每一层为其上层提供服务.例如:web开发中我们常常将某些常用的RESTful接口抽象出一个service层. 客户端-服务端模式 客户端和服务端分离,从而解耦.通过 ...

  10. 使用curl 上传文件,multipart/form-data

    使用curl 上传文件,multipart/form-data 1. 不使用-F,curl内置multipart/form-data功能: 2. 文件内容与真实数据无关,用abc代替数据,依然可以上传 ...