Netty Hello Word-copy

 

概述
https://github.com/csy512889371/learndemo/netty/NettyHello
netty版本大致版本分为 netty3.x 和 netty4.x、netty5.x

netty可以运用在那些领域?
1、分布式进程通信

例如: hadoop、dubbo、akka等具有分布式功能的框架,底层RPC通信都是基于netty实现的,这些框架使用的版本通常都还在用netty3.x

2、游戏服务器开发

最新的游戏服务器有部分公司可能已经开始采用netty4.x 或 netty5.x

1、netty服务端hello world案例
SimpleChannelHandler 处理消息接收和写
{
messageReceived接收消息
channelConnected新连接,通常用来检测IP是否是黑名单
channelDisconnected链接关闭,可以再用户断线的时候清楚用户的缓存数据等
}
2、netty客户端hello world案例
channelDisconnected与channelClosed的区别

channelDisconnected只有在连接建立后断开才会调用

channelClosed无论连接是否成功都会调用关闭资源

netty server 服务端
1、初始化ServerBootstrap,并注入NioServerSocketChannelFactory,用于创建通道(channel)等。从这里可以看出是通过Nio的方式来处理的,factory中放入两个线程池,主要用于接收connect和message。

2、MyHandler继承了SimpleChannelHandler,并且重写了方法:channelClosed、channelConnected、messageReseived,方法的参数为ChannelHandlerContext和ChannelEvent。ChannelHandlerContext为通道上下文,event中便带有消息和连接的信息。

channelConnected方法在接到来自客户端的连接时触发(这里只是打印了收到的连接的信息),所以在执行telnet命令时,看到控制台会有相应的输出。 MessageReseived方法在接收到消息是会触发,这里会交给processMessage方法处理,这里只是简单的把接收到的信息写回客户端。所以在命令行窗口中会看到我们写入的字母信息。

ChannelClosed方法在关闭连接的时候被调用,当我们关闭命令行窗口的时候,就会看到控制台打印出相应的信息。

当然,ChannelHander的接口不止这么三个,除了SimpleChannelHandler以外还有很特殊的实现,这里只做简单介绍。

3、初始化完成之后,我们调用server.config(int port)方法注入需要绑定的端口信息

Server

import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;

/**
* netty服务端入门
*/
public class Server {

public static void main(String[] args) {

//服务类
ServerBootstrap bootstrap = new ServerBootstrap();

//boss线程监听端口,worker线程负责数据读写
ExecutorService boss = Executors.newCachedThreadPool();
ExecutorService worker = Executors.newCachedThreadPool();

//设置niosocket工厂
bootstrap.setFactory(new NioServerSocketChannelFactory(boss, worker));

//设置管道的工厂
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {

@Override
public ChannelPipeline getPipeline() throws Exception {

ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("helloHandler", new HelloHandler());
return pipeline;
}
});

bootstrap.bind(new InetSocketAddress(10101));

System.out.println("start!!!");

}

}
HelloHandler

import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;

/**
* 消息接受处理类
*/
public class HelloHandler extends SimpleChannelHandler {

/**
* 接收消息
*/
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {

String s = (String) e.getMessage();
System.out.println(s);

//回写数据
ctx.getChannel().write("hi");
super.messageReceived(ctx, e);
}

/**
* 捕获异常
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
System.out.println("exceptionCaught");
super.exceptionCaught(ctx, e);
}

/**
* 新连接
*/
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("channelConnected");
super.channelConnected(ctx, e);
}

/**
* 必须是链接已经建立,关闭通道的时候才会触发
*/
@Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("channelDisconnected");
super.channelDisconnected(ctx, e);
}

/**
* channel关闭的时候触发
*/
@Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("channelClosed");
super.channelClosed(ctx, e);
}
}
运行程序,打开命令行,输入:telnet 127.0.0.1 10101

netty client netty 客户端
import java.net.InetSocketAddress;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;

/**
* netty客户端入门
*/
public class Client {

public static void main(String[] args) {

//服务类
ClientBootstrap bootstrap = new ClientBootstrap();

//线程池
ExecutorService boss = Executors.newCachedThreadPool();
ExecutorService worker = Executors.newCachedThreadPool();

//socket工厂
bootstrap.setFactory(new NioClientSocketChannelFactory(boss, worker));

//管道工厂
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {

@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("hiHandler", new HiHandler());
return pipeline;
}
});

//连接服务端
ChannelFuture connect = bootstrap.connect(new InetSocketAddress("127.0.0.1", 10101));
Channel channel = connect.getChannel();

System.out.println("client start");

Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("请输入");
channel.write(scanner.next());
}
}

}
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;

/**
* 消息接受处理类
*/
public class HiHandler extends SimpleChannelHandler {

/**
* 接收消息
*/
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {

String s = (String) e.getMessage();
System.out.println(s);

super.messageReceived(ctx, e);
}

/**
* 捕获异常
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
System.out.println("exceptionCaught");
super.exceptionCaught(ctx, e);
}

/**
* 新连接
*/
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("channelConnected");
super.channelConnected(ctx, e);
}

/**
* 必须是链接已经建立,关闭通道的时候才会触发
*/
@Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("channelDisconnected");
super.channelDisconnected(ctx, e);
}

/**
* channel关闭的时候触发
*/
@Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("channelClosed");
super.channelClosed(ctx, e);
}

}

概述
netty 核心代码基于nio 实现多线程。下面是简化版的netty代码

https://github.com/csy512889371/learndemo/tree/master/netty/NIONetty

代码

Boss

import java.nio.channels.ServerSocketChannel;
/**
* boss接口
*
*
*/
public interface Boss {

/**
* 加入一个新的ServerSocket
* @param serverChannel
*/
public void registerAcceptChannelTask(ServerSocketChannel serverChannel);
}
Worker

import java.nio.channels.SocketChannel;
/**
* worker接口
*
*
*/
public interface Worker {

/**
* 加入一个新的客户端会话
* @param channel
*/
public void registerNewChannelTask(SocketChannel channel);

}
NioSelectorRunnablePool

import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import com.cn.NioServerBoss;
import com.cn.NioServerWorker;
/**
* selector线程管理者
*
*
*/
public class NioSelectorRunnablePool {

/**
* boss线程数组
*/
private final AtomicInteger bossIndex = new AtomicInteger();
private Boss[] bosses;

/**
* worker线程数组
*/
private final AtomicInteger workerIndex = new AtomicInteger();
private Worker[] workeres;


public NioSelectorRunnablePool(Executor boss, Executor worker) {
initBoss(boss, 1);
initWorker(worker, Runtime.getRuntime().availableProcessors() * 2);
}

/**
* 初始化boss线程
* @param boss
* @param count
*/
private void initBoss(Executor boss, int count) {
this.bosses = new NioServerBoss[count];
for (int i = 0; i < bosses.length; i++) {
bosses[i] = new NioServerBoss(boss, "boss thread " + (i+1), this);
}

}

/**
* 初始化worker线程
* @param worker
* @param count
*/
private void initWorker(Executor worker, int count) {
this.workeres = new NioServerWorker[count];
for (int i = 0; i < workeres.length; i++) {
workeres[i] = new NioServerWorker(worker, "worker thread " + (i+1), this);
}
}

/**
* 获取一个worker
* @return
*/
public Worker nextWorker() {
return workeres[Math.abs(workerIndex.getAndIncrement() % workeres.length)];

}

/**
* 获取一个boss
* @return
*/
public Boss nextBoss() {
return bosses[Math.abs(bossIndex.getAndIncrement() % bosses.length)];
}

}
AbstractNioSelector

import java.io.IOException;
import java.nio.channels.Selector;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;

import com.cn.pool.NioSelectorRunnablePool;

/**
* 抽象selector线程类
*
*
*
*/
public abstract class AbstractNioSelector implements Runnable {

/**
* 线程池
*/
private final Executor executor;

/**
* 选择器
*/
protected Selector selector;

/**
* 选择器wakenUp状态标记
*/
protected final AtomicBoolean wakenUp = new AtomicBoolean();

/**
* 任务队列
*/
private final Queue<Runnable> taskQueue = new ConcurrentLinkedQueue<Runnable>();

/**
* 线程名称
*/
private String threadName;

/**
* 线程管理对象
*/
protected NioSelectorRunnablePool selectorRunnablePool;

AbstractNioSelector(Executor executor, String threadName, NioSelectorRunnablePool selectorRunnablePool) {
this.executor = executor;
this.threadName = threadName;
this.selectorRunnablePool = selectorRunnablePool;
openSelector();
}

/**
* 获取selector并启动线程
*/
private void openSelector() {
try {
this.selector = Selector.open();
} catch (IOException e) {
throw new RuntimeException("Failed to create a selector.");
}
executor.execute(this);
}

@Override
public void run() {

Thread.currentThread().setName(this.threadName);

while (true) {
try {
wakenUp.set(false);

select(selector);

processTaskQueue();

process(selector);
} catch (Exception e) {
// ignore
}
}

}

/**
* 注册一个任务并激活selector
*
* @param task
*/
protected final void registerTask(Runnable task) {
taskQueue.add(task);

Selector selector = this.selector;

if (selector != null) {
if (wakenUp.compareAndSet(false, true)) {
selector.wakeup();
}
} else {
taskQueue.remove(task);
}
}

/**
* 执行队列里的任务
*/
private void processTaskQueue() {
for (;;) {
final Runnable task = taskQueue.poll();
if (task == null) {
break;
}
task.run();
}
}

/**
* 获取线程管理对象
* @return
*/
public NioSelectorRunnablePool getSelectorRunnablePool() {
return selectorRunnablePool;
}

/**
* select抽象方法
*
* @param selector
* @return
* @throws IOException
*/
protected abstract int select(Selector selector) throws IOException;

/**
* selector的业务处理
*
* @param selector
* @throws IOException
*/
protected abstract void process(Selector selector) throws IOException;

}
NioServerBoss

import java.io.IOException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.Executor;

import com.cn.pool.Boss;
import com.cn.pool.NioSelectorRunnablePool;
import com.cn.pool.Worker;
/**
* boss实现类
*
*
*/
public class NioServerBoss extends AbstractNioSelector implements Boss{

public NioServerBoss(Executor executor, String threadName, NioSelectorRunnablePool selectorRunnablePool) {
super(executor, threadName, selectorRunnablePool);
}

@Override
protected void process(Selector selector) throws IOException {
Set<SelectionKey> selectedKeys = selector.selectedKeys();
if (selectedKeys.isEmpty()) {
return;
}

for (Iterator<SelectionKey> i = selectedKeys.iterator(); i.hasNext();) {
SelectionKey key = i.next();
i.remove();
ServerSocketChannel server = (ServerSocketChannel) key.channel();
// 新客户端
SocketChannel channel = server.accept();
// 设置为非阻塞
channel.configureBlocking(false);
// 获取一个worker
Worker nextworker = getSelectorRunnablePool().nextWorker();
// 注册新客户端接入任务
nextworker.registerNewChannelTask(channel);

System.out.println("新客户端链接");
}
}


public void registerAcceptChannelTask(final ServerSocketChannel serverChannel){
final Selector selector = this.selector;
registerTask(new Runnable() {
@Override
public void run() {
try {
//注册serverChannel到selector
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (ClosedChannelException e) {
e.printStackTrace();
}
}
});
}

@Override
protected int select(Selector selector) throws IOException {
return selector.select();
}

}
NioServerWorker

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.Executor;

import com.cn.pool.NioSelectorRunnablePool;
import com.cn.pool.Worker;
/**
* worker实现类
*
*
*/
public class NioServerWorker extends AbstractNioSelector implements Worker{

public NioServerWorker(Executor executor, String threadName, NioSelectorRunnablePool selectorRunnablePool) {
super(executor, threadName, selectorRunnablePool);
}

@Override
protected void process(Selector selector) throws IOException {
Set<SelectionKey> selectedKeys = selector.selectedKeys();
if (selectedKeys.isEmpty()) {
return;
}
Iterator<SelectionKey> ite = this.selector.selectedKeys().iterator();
while (ite.hasNext()) {
SelectionKey key = (SelectionKey) ite.next();
// 移除,防止重复处理
ite.remove();

// 得到事件发生的Socket通道
SocketChannel channel = (SocketChannel) key.channel();

// 数据总长度
int ret = 0;
boolean failure = true;
ByteBuffer buffer = ByteBuffer.allocate(1024);
//读取数据
try {
ret = channel.read(buffer);
failure = false;
} catch (Exception e) {
// ignore
}
//判断是否连接已断开
if (ret <= 0 || failure) {
key.cancel();
System.out.println("客户端断开连接");
}else{
System.out.println("收到数据:" + new String(buffer.array()));

//回写数据
ByteBuffer outBuffer = ByteBuffer.wrap("收到\n".getBytes());
channel.write(outBuffer);// 将消息回送给客户端
}
}
}

/**
* 加入一个新的socket客户端
*/
public void registerNewChannelTask(final SocketChannel channel){
final Selector selector = this.selector;
registerTask(new Runnable() {
@Override
public void run() {
try {
//将客户端注册到selector中
channel.register(selector, SelectionKey.OP_READ);
} catch (ClosedChannelException e) {
e.printStackTrace();
}
}
});
}

@Override
protected int select(Selector selector) throws IOException {
return selector.select(500);
}

}
ServerBootstrap

import java.net.SocketAddress;
import java.nio.channels.ServerSocketChannel;

import com.cn.pool.Boss;
import com.cn.pool.NioSelectorRunnablePool;
/**
* 服务类
*
*
*/
public class ServerBootstrap {

private NioSelectorRunnablePool selectorRunnablePool;

public ServerBootstrap(NioSelectorRunnablePool selectorRunnablePool) {
this.selectorRunnablePool = selectorRunnablePool;
}

/**
* 绑定端口
* @param localAddress
*/
public void bind(final SocketAddress localAddress){
try {
// 获得一个ServerSocket通道
ServerSocketChannel serverChannel = ServerSocketChannel.open();
// 设置通道为非阻塞
serverChannel.configureBlocking(false);
// 将该通道对应的ServerSocket绑定到port端口
serverChannel.socket().bind(localAddress);

//获取一个boss线程
Boss nextBoss = selectorRunnablePool.nextBoss();
//向boss注册一个ServerSocket通道
nextBoss.registerAcceptChannelTask(serverChannel);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Start

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import com.cn.pool.NioSelectorRunnablePool;
/**
* 启动函数
*
*
*/
public class Start {

public static void main(String[] args) {

//初始化线程
NioSelectorRunnablePool nioSelectorRunnablePool = new NioSelectorRunnablePool(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());

//获取服务类
ServerBootstrap bootstrap = new ServerBootstrap(nioSelectorRunnablePool);

//绑定端口
bootstrap.bind(new InetSocketAddress(10101));

System.out.println("start");
}

}

Netty3 核心代码-copy的更多相关文章

  1. 【五子棋AI循序渐进】关于VCT,VCF的思考和核心代码

    前面几篇发布了一些有关五子棋的基本算法,其中有一些BUG也有很多值得再次思考的问题,在框架和效果上基本达到了一个简单的AI的水平,当然,我也是初学并没有掌握太多的高级技术.对于这个程序现在还在优化当中 ...

  2. Darwin Streaming Server 核心代码分析

    基本概念 首先,我针对的代码是Darwin Streaming Server 6.0.3未经任何改动的版本. Darwin Streaming Server从设计模式上看,采用了Reactor的并发服 ...

  3. 【转】Darwin Streaming Server 核心代码分析

    无意中看到了dqzhangp的一篇博客,分析了DSS的核心架构,读完顿时感觉豁然开朗,茅塞顿开,写得非常的鞭辟入里,言简意赅,我想没有相当的功力是写不出这样的文章的,情不自禁转到自己空间来,生怕弄丢了 ...

  4. Android发送短信核心代码

    核心代码:(1)SmsManager manager = SmsManager.getDefault(); //获得默认的消息管理器(2)ArrayList<String> list = ...

  5. [html5+java]文件异步读取及上传核心代码

    html5+java 文件异步读取及上传关键代码段 功能: 1.多文件文件拖拽上传,file input 多文件选择 2.html5 File Api 异步FormData,blob上传,图片显示 3 ...

  6. .NET核心代码保护策略-隐藏核心程序集

    经过之前那个道德指责风波过后也有一段时间没写博客了,当然不是我心怀内疚才这么久不写,纯粹是程序员的通病..怎一个懒字了得,本来想写一些长篇大论反讽一下那些道德高人的.想想还是算了,那样估计会引来新一波 ...

  7. 处理部分WordPress核心代码或功能,让你的网站更快

    处理部分WordPress核心代码或功能,让你的网站更快 http://www.wpdaxue.com/speed-up-wordpress.html

  8. OC 冒泡排序 -- 核心代码

    //冒泡 核心代码 for (int i = 0; i < array.count - 1; i++) { int a = [array[i] intValue]; for (int j = i ...

  9. .NET核心代码保护策略

    .NET核心代码保护策略-隐藏核心程序集 经过之前那个道德指责风波过后也有一段时间没写博客了,当然不是我心怀内疚才这么久不写,纯粹是程序员的通病..怎一个懒字了得,本来想写一些长篇大论反讽一下那些道德 ...

  10. js小功能合集:计算指定时间距今多久、评论树核心代码、字符串替换和去除。

    1.计算指定时间距今多久 var date1=new Date('2017/02/08 17:00'); //开始时间 var date2=new Date(); //当前时间 var date3=d ...

随机推荐

  1. Docker 自定义镜像Dockerfile使用详细教程

    认识 Dockerfile 文件 Dockerfile 用于构建 Docker 镜像,Dockerfile 文件是由一行行命令语句 组成,基于这些命令即可以构建一个镜像 比如下面就是一个Dockefi ...

  2. 如何手写实现 JSON Parser

    JSON.parse 是我们在前端开发中经常会用到API,如果我们要自己实现一个JSON.parse,我们应该怎么实现呢?今天我们就试着手写一个JSON Parser,了解下其内部实现原理. JSON ...

  3. 2024 BUPT Programming Contest F

    简要题意 多测,给定一个 \(n \times n\) 矩阵,矩阵中的每一个元素的计算方式如下: 矩阵的行和列唯一决定两个整数对 \((a, b)\),矩阵第 \(a(0 \le a < n)\ ...

  4. git rebase -i的时候用的不是 vi 编辑器是 nano编辑器不会用

    今天给同事 rebase 代码 发现 git fetch && git rebase -i origin/develop 的时候 出现了 那个 nano 编辑器的界面 不会用,和vim ...

  5. SAX,DOM,JAXP,JDOM,DOM4J比较分析

    第一:首先介绍一下SAX,DOM,JAXP,JDOM,DOM4J的基本知识:(注意:至于 JAXP JAXB JAXM JAXR JAX-RPC 分别指什么,查看http://gceclub.sun. ...

  6. MySQL原理简介—9.MySQL索引原理

    大纲 1.磁盘数据页的存储结构 2.没有索引数据库如何搜索数据 3.在表中插入数据时如何进行页分裂 4.如何设计主键索引及如何根据主键索引查询 5.索引的物理存储结构 6.更新数据时自动维护的聚簇索引 ...

  7. LGR-204-Div.2

    Contest link 质量不错的比赛. A 比较明显的题,贪心往下做就可以. #include <bits/stdc++.h> using i64 = long long; const ...

  8. 使用redis 的订阅服务

    1.业务使用场景 我们在使用表单动态添加字段,如果新增字段,再保存数据,这个时候就会出错,出错的原因是seata 再本地缓存元数据,修改物理表的时候,这个元数据并没有发生变化,因此需要刷新元数据,因为 ...

  9. 借助AI助手分析LlamaIndex的工作流可视化

    接续上次的讨论,我们上次主要分析了LlamaIndex工作流的核心流程,当前还剩下一行代码需要关注,那就是关于工作流的可视化.今天我们的目标是深入理解这一可视化部分的主要流程,并且对其大体的实现方式进 ...

  10. 【Amadeus原创】更改docker run启动参数

    经过一整天的摸索,答案: 没法直接修改.只能另外创建. 但是还好不用完全重头来,用docker commit命令可以基于当前修改的内容创建一个新的image. 执行docker 看看帮助先: Comm ...