模拟实现NIO CSFramework

什么是NIO?

Java NIO ( New IO 或 Non Blocking IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。

传统的IO是单向的。往程序中读取数据需要输入流。从程序中写出数据需要输出流。它是直接面向流的。直接从流中读取和写入数据。

NIO是双向的,它是面向缓冲区的。在数据源与目的地之间建立传输通道。利用通道将缓冲区中的数据读取和写入,双端之间的数据都是存在于缓冲区中。通道主要是负责连接的,真正的数据是在缓冲区中。

NIO实现

java定时器的实现

java定时器.
这里简要述说一下:
设置一个启动线程,以及一个工作线程。工作线程是一个实现了Runnable的接口,其中方法是我们规定的要做的事(task()),(利用default关键字,让这个run方法执行task方法即可),对于启动线程,让这个工作线程作为类成员,并设置延迟时间以及实现Runnable接口。其工作原理就是:当使用启动线程并设置成员ITimeTask和延迟时间后,调用startup方法,其作用是开启一个线程,在这个线程中,在此new Thread(ITimeWork).start()。这样就启动了ITimeWork去执行task方法。在这里插入图片描述

通信信道实现

这里我做的是发送消息是使用的一样的。client端还是使用以前那种读写模式,服务器端对于读消息会有改进,为了代码复用,写一个基础communication来让服务器端和客户端继承。
在这里插入图片描述
那么除了发送消息还需要有读消息,因为说了client端是使用以前相同处理方式,这里就只贴一下怎么读消息的。
读消息
对于服务器端在发送消息还是一样的,这里不再赘述。对于消息的读时我们需要使用的是一种新的方式,利用dis提供的available方法,(int count = this.dis.available();)他返回的是一个整型量,其实就是看缓冲区中是否有消息。小于0就不处理,当扫描到count大于0就说明来消息了,这时才去处理。以前编写的是用一个while循环,一直在等待消息的到来,以后会开启一个线程来对其轮询,轮询发现有消息就处理。这里降低了cpu的开销,不必一直等待而是一段时间去查看,降低了开销但是也增加了延迟。

消息处理实现

对于消息的处理这里使用到了分发器模式。对于处理消息其实也和以前差不多,但是值得注意的是,这里不再直接有响应。因为如果有响应的话在客户端就会出现阻塞,所以我们就发送一个请求后完毕即可。先不说那么多,首先看怎么处理消息才会达到非阻塞。因为serverConversation和clientConversation里面都继承了各自的communication。所以直接进行实现就好。但是实现也各有不同,首先在服务器端接收到消息后他不能是直接处理(这样会有阻塞),这里采用的是利用线程池去执行,为什么使用线程池?对于服务器端它会接收到很多个客户端的请求,如果每个客户端都要执行完后才去处理下面的客户端,这样的话等待时间是真的多,所以利用线程池,并且线程池更便利于线程的管理。对于客户端,因为他不会处理多个服务器的消息或者说同一时间不会处理很多的消息,那么在接收消息后直接处理就好,这里是不会出现阻塞的。·

首先看客户端处理消息:
在这里插入图片描述
在这里插入图片描述
这里就是一个简单的反射机制的使用(规定了处理消息的方法是deal+消息的具体信息)。
例如:
在这里插入图片描述
这里对于Message的处理是使用的一个接口,对每个不同的action进行不同的处理。

服务器处理消息:
在这里插入图片描述
这里是一个内部类其实现了Runnable接口
在这里插入图片描述
下面的处理就是相同的了–利用反射机制执行不同的方法。

请求与响应实现

上面实际已经提到了请求与响应,现在大致说一下。对于客户端sendMessage来实现发送一个请求信息,服务器对于请求信息的处理是利用一个线程池处理,这样就可以做到所谓的NIO。以前这里处理完一个请求后会直接返回一个响应,但是这里是没有的,为什么没有呢?因为这里不会产生一个响应,真正的响应是在app层去实现,再次调用一个sendMessage,在客户端会利用分发器去和工厂模式去处理对应的请求(这就是以前所谓的响应)
client:
在这里插入图片描述
在这里插入图片描述
server也是和client一样的,只是从线程池中的内部类来对应上述的方法。

这里再叫简单讲一下工厂模式构建actionBean吧。这里使用的是注解方式。首先规定了注解类和注解方法以及注解参数的三个注解,然后构建了两个定义类,一个是action-method定义类,一个是method-parameter定义了类。
在这里插入图片描述
在这里插入图片描述
这里讲解一下为什么parameter定义存在一个name属性,因为在我的工具ArgueMaker需要参数名以及参数类型的值进行存储和解析。所以我也写了一个参数的注解。

在工厂中及进行包装bean,然后存放。其实就是一个包扫描问题,扫描注解兵填充参数,加入pool中保存就好,要用时进行get。

所以在defaultProcessor中设置参数后获得参数就可以进行invoke了。

对客户端的轮询操作

上述说过了一个轮询操作,下面讲述另一个轮询操作。轮询客户端是否在线。为什么需要这个轮询?以前使用的是一个while死循环,当报异常就是对方异常掉线了,但是现在没有死循环,就不会随时监测到对方是否还在线。所以需要一个轮询操作来确定在线,当不在线时就及进行剔除。

sever有一个成员-clientPool。这是ClientPool类的对象,这里面记录了所有的连接到server的client。
下面看一下怎么加入clientPool中的。
server类中有两个方法(add和remove)
在这里插入图片描述
因为server会开启侦听线程,侦听到连接请求后会建立连接兵new serverconversation,serverConversation中会及进行生成id还可以监测是否加入到server的clientPool中。
在这里插入图片描述
这样只要有这个clientPool就可以对client进行轮询了。
上面讲了信息的轮询,这次将客户端是否存在的轮询。
在这里插入图片描述
这就是具体的操作,这里使用了一个小技巧,在clientPool中的checkAllClient中时遍历所有的在线客户端,然后做啥事不管利用金额口来搞定,通过接口的实现类来规定该干嘛。这是真的挺犀利的。
在这里插入图片描述
这里用到了java定时器,设置task就完成了,因为server开启前时设置了的,只要在设置IUserTask时用这个是西安类就好。发送sayHello后会调用到writeUtf如果出异常就是对端异常掉线,因为都是经过继承来的真实实现是在ServerConversation中实现的,因为serverConversation中有Server成员,这样就可以更改client的Online状态了。

总结工作流程

这里进行总结一下流程,首先服务器开启后侦听客户端的连接,当侦听到连接后会new ServerConversation,在serverConversation中实现通信,这之前会将这次连接加入到一个ClientPool中以便以后轮询,开启后并向客户但发送一个id。然后就可以进行通信了。这里讲述一下关于通信时的过程。

客户端向服务器发送一个消息,服务器不是立刻得到这个消息内容的,他是通过一个线程来运行轮询消息的。首先时遍历所有的在线的ServerConversation,并调用receive方法。这样就可以看是否有消息,如果发现有消息就会利用线程池来execute来执行分发器的逻辑。在找到该执行的方法后利用反射执行方法就好。

对于action的处理:
处理到上述的反射执行方法,他会去调用一个接口类的实现类中的方法。并通过对参数的填充以及从ActionMethodfactory中获取action对应的ActiionMethodDefinition就可以执行了。对于参数的返回是app层发送一个请求给客户端,让客户端解析就好。

对于轮询:
上述总结讲到了消息的轮询,对于客户端是否在线的轮询还是挺巧妙的,利用的是接口作为参数以及定时器解决的。到特定的时间后就开启执行轮询,每一次轮询都是先修改状态然后再进行遍历删除。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值