【NIO】更简单的nio使用方式

接触nio也有好几年了,最开始摸不着头脑,资料很少,网上的资料都是翻来覆去的抄袭,基本上对于自己的学习没有大帮助。

后来遇到了xsocket,觉得用起来还可以,挺方便,api也很简洁。不过这个库的用户不多,后来作者也停止了开发。

然后就是mina netty,这些不用说,了解nio的人都知道它们。不过想用好它们也不是那么容易。里面有各种回调,各种future,当你在处理网络事件的时候,如果想在发起一个连接,那回调代码就已经成翔。并非批评这种方式不好,只不过它不符合我这样的懒人、笨人使用。因为,就是做个接个连接、发起个连接而已,越直观越好。

于是就想找一种解决办法,改变当前的不爽。最初的努力方向,是通过锁、等待通知事件的机制进行封装,这样在一定程度上可以解决一部分问题,不过我设定的环境是处理网络事件比较频繁的环境,所以,锁的开销会潜在的比较高,也会显著的降低吞吐量。最重要的因素是:复杂度,应用层的复杂度得到一定程度的环境,不过底层代码的编写复制度还是很高,回调很多,很难直观的看到代码的全貌、流程,所以经过了很长一段的时间的尝试之后,决定换个角度看看。

于是重新审视我在处理的事情,其实就是事件的处理,事件的处理常用方法就是消息机制,发送消息,比如qt  mfc等等,都是用消息机制。觉得这样的方式不是我想要的。我想要一种类似线程的东西,但是挂起和恢复可以由自己来控制,而且开销要足够低。我知识面不算很宽,所以,当时还不知道这东西应该是什么,于是就google一把,这时协程(coroutine,fiber)进入了我的视线,协程的定义、以及用户态调度的方式,都符合要求,潜意思中感到:找到合适办法。

于是就看了很多协程相关的资料、文章。并了解了协程的现有实现:go有,c#有,lua有,boost有,dlang有,java有kilim,linux有ucontext。反正有很多。最先选择了看kilim,看了一段时间觉得很晕乎,于是换,看boost,还是是很晕乎,没看懂它是怎么实现的。这时,正在学dlang,dlang里有个vibe.d的库,这是一个庞大的库,http  tcp udp的封装都有,而且它也是开源的,于是,就先用它写了一段时间的程序,不知道我姿势不对,还是它的库不稳定,反正是出各种bug,我也就不停的调试。用了几个月,里面的大致概念基本懂了,但是它还是很容易出错,程序很容易崩溃。于是,就用epoll和dlang本身的fiber封装了一个新的库,这里重要的改进是加入了空指针的检测,让程序不再轻易崩溃。在此过程中,学会了基本的协程调度以及和epoll网络事件的处理,以及两者的结合方式。

而实际工作中,使用的还是java,用了kilim,也用了netty,觉得这种结合方式很不方便,事件需要在两个线程间不停传递。于是又翻看了kilim的源码,除了注入部分,其余的大致能看懂,而我最关心的其实是调度部分,kilim的调度使用的是线程间的调度方式,使用了很多锁,隐隐觉得不妥,我需要的是在单线程情况下能高效运行的方法。而且传统的epoll程序正是这样,所以,只需要把我在dlang里做的工作搬到这里即可。

说干就干,平时早上6点起床,写到8点,周末连续写两天。经过两个周末,一周多的时间,我终于把kilim和nio结合到一起了,并写了一些常用的工具,比如协程间的协调(等待、通知),等等。我给它取名:dawn。

现在使用nio的方式就很符合我的预期,写起来很直观,代码是顺序写的,而不是回调:

看个例子:

Echo Server,这种server的功能很简单,就是把服务收到的所有数据发回客户端。那看在dawn里怎么写:

首先,所有协程都是在调度器中运行的,要创建一个调度器

Scheduler sch = new Scheduler();

其次,要创建一个协程,来加载我们的程序:

new Task() {

@Override

public void execute() throws Pausable, Exception {

System.out.println("boostrap..");

TcpServer server = new TcpServer("0.0.0.0", 10000) {

@Override

protected void onAccepted(TcpChannel ch) {

processConnection(ch);

}

};

server.start();

}

}.startOn(sch); //因为执行这行代码的时候 ,还处于调度器线程之外,所以,必须指定在哪个调度器上执行。

这里创建了一个Task即协程,并让他在sch上运行。

execute方法体里,就是初始化代码,在所有地址、端口10000上创建了一个tcp服务器,并在接收到连接的时候调用processConnection方法。

接下来我们来看这个方法

static void processConnection(final TcpChannel ch) {

new Task() {

@Override

public void execute() throws Pausable, Exception {

System.out.println("reading.");

ScalableDirectBuf buf = ScalableDirectBuf.allocateFromTlsCache();  //分配一个buffer

int n = 0;

while (true) {

n = ch.readSome(buf);  //读数据,这里会阻塞,直到读到数据,或者抛出网络异常

if (n > 0) {

ch.writeAll(buf); //写数据,这里也会阻塞,直到写完所有数据。

}

count++;

buf.compact(); //压缩buffer,抛弃已经消耗的数据,并释放出空间,未消耗掉的数据,还会继续留在buffer中。

}

}

}.start();//此时,代码已经在调度器线程执行,所以不需要指定调度器,默认使用父协程所在的调度器。

}

最后,启动调度器,在启动调度器之前,所有协程的execute方法都不会执行。

sch.start();

最后,我们可以用telnet 127.0.0.1 10000连上这个服务器,并发送数据,会把你发送的数据回显在telnet客户端上。

好吧,先写到这把,歇会。更多信息可以到github上去看:

https://github.com/zhmt/dawn

时间: 2024-10-18 09:01:57

【NIO】更简单的nio使用方式的相关文章

数据可视化分析除了需要编码的Python,还有更简单的方式吗?

大数据.数据分析的兴起和火爆,也带动了数据可视化的广泛应用.说起数据分析和可视化的关系,就好比你为一堆散乱的拼图写了一份说明,告诉他这个数据是什么样子,代表什么.可以说,数据可视化虽然不是必不可少的,但却是可以加快效率,为报告锦上添花的.今天,说起数据可视化,我们就不得不谈一下数据可视化工具了.主要说到的这个工具也是最近在数据分析圈比较受追捧的一个软件--Python. 数据可视化分析除了需要编码的Python,还有更简单的方式吗?Python虽好,但是需要编程才能实现数据的可视化,编程对于用户

辛星和您用更简单的方式去实现PHP中的验证码

说实话,提到验证码我想大家都不会陌生,确实,验证码还是挺常见的,现在搜索一下PHP的验证码类简直是海量的数据,那我们今天就来实现一个自己的验证码把,不过它比较简单,这也是我说的用更简单的方式去实现一个验证码. 总的来说分成两步,第一步就是先实现一个验证码,第二步就是通过这个验证码来进行验证,我们先看一下如何去实现这个验证码,当然这里需要用到gd库的知识,请看下面的代码示例: <?php //首先要开启session session_start(); //说明这是一张图片 header("C

Java NIO:IO与NIO的区别

一.概念 NIO即New IO,这个库是在JDK1.4中才引入的.NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多.在Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO. 二.NIO和IO的主要区别 下表总结了Java IO和NIO之间的主要区别: IO NIO 面向流 面向缓冲 阻塞IO 非阻塞IO 无 选择器 1.面向流与面向缓冲 Java IO和NIO之间第一个最大的区别是,IO是面向流的,NIO是

(四:NIO系列) Java NIO Selector

出处:Java NIO Selector 1.1. Selector入门 1.1.1. Selector的和Channel的关系 Java NIO的核心组件包括: (1)Channel(通道) (2)Buffer(缓冲区) (3)Selector(选择器) 其中Channel和Buffer比较好理解 ,联系也比较密切,他们的关系简单来说就是:数据总是从通道中读到buffer缓冲区内,或者从buffer写入到通道中. 选择器和他们的关系又是什么? 选择器(Selector) 是 Channel(通

让开发更简单 —— Coding Enterprise 发布

今天,我们很高兴地宣布 Coding Enterprise 发布了 -- Coding Enterprise 是 CODING 专为企业打造的软件开发协作平台,提供了针对中小型企业的公有云版本和针对大型企业的私有云版本,功能覆盖所有的开发场景,可以帮助企业更高效便捷地进行开发协作,真正实现一站式开发. 简单易用,安全高效 CODING 团队拥有 3 年多的互联网平台级产品开发和运营经验,旗下 Coding.net 云端软件开发协作平台已积累了 35 万多名的用户及 60 万多个项目,包括 Lin

【转】【C#】C# 5.0 新特性——Async和Await使异步编程更简单

一.引言 在之前的C#基础知识系列文章中只介绍了从C#1.0到C#4.0中主要的特性,然而.NET 4.5 的推出,对于C#又有了新特性的增加--就是C#5.0中async和await两个关键字,这两个关键字简化了异步编程,之所以简化了,还是因为编译器给我们做了更多的工作,下面就具体看看编译器到底在背后帮我们做了哪些复杂的工作的. 二.同步代码存在的问题 对于同步的代码,大家肯定都不陌生,因为我们平常写的代码大部分都是同步的,然而同步代码却存在一个很严重的问题,例如我们向一个Web服务器发出一个

Rsession让Java调用R更简单

Rsession让Java调用R更简单 R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大. R语言作为统计学一门语言,一直在小众领域闪耀着光芒.直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器.随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长.现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言. 要成为有理想的极客,我们不能停留在语法上,要掌握牢固的数学,概率,统计知识,同时还要有创新精神,把R语言发挥

TFS 2010 让安装更简单,也让VSS成为历史

一转眼VS 2010 RC(Release Candidate)版本号已经公布一月多了,RTM(Release To Manufacturer)版本号也快妥了,已经进入了最后的倒计时,仅仅等4月12号公布了.TFS 2010也将一起正式公布,相对于2005和2008,2010将是具有里程碑意义的一个版本号,就像它总设计师Brian Harry在以下的Channel 9採訪中所描写叙述的:“TFS 2005是TFS 1.0版,2008则是1.5,而2010则是2.0版”. Brian Harry:

OkHttpUtils-2.0.0 升级后改名 OkGo,全新完美支持 RxJava,比 Retrofit 更简单易用。

okhttp-OkGo 项目地址:jeasonlzy/okhttp-OkGo 简介:OkHttpUtils-2.0.0 升级后改名 OkGo,全新完美支持 RxJava,比 Retrofit 更简单易用.该库是封装了 okhttp 的网络框架,支持大文件上传下载,上传进度回调,下载进度回调,表单上传(多文件和多参数一起上传),链式调用,可以自定义返回对象,支持 Https 和自签名证书,支持 cookie 的持久化和自动管理,支持四种缓存模式缓存网络数据,支持 301 和 302 重定向,扩展了