1 BIO
1.1 信息的传输以及通道的建立
1.1.1 信息的传输
BIO的信息通过流的方式传递,依靠outputstream和dataoutputstream等传输数据,dataoutputstream中对不同类型变量调用不同次数的outputstream中的write方法来进行处理,所以本质上只需要用outptustream就行了,只有因为字符流更加便于交互所以在外面套了一层data流。
1.1.2 服务端如何接受信息
服务端通过循环调用accept获取远程主机信息并且建立与客户端相同的信息通道进行通信。
1.1.3 基于Socket的信息通道建立
//这是Socket类中getOutputStream方法的实现
//PrivilegedExceptionAction指的是可抛出异常的特权执行代码块,run的返回值作为doPrivileged的返回值,socket.this指的是内部类外的那个持有的对象(SocketImpl的实现类),最后会返回一个SocketOutputStream对象
os = (OutputStream)AccessController.doPrivileged(new PrivilegedExceptionAction<OutputStream>() {
public OutputStream run() throws IOException {
return Socket.this.impl.getOutputStream();
}
});
AccessController.doPrivileged作用:给没有权限的代码一个访问特定资源的机会,不同的代码通过codesource类描述其位置以及证书,也就是不同代码权限是不同的,而这些权限包括有读写文件,监听,读写socket和退出java系统等。在执行一段代码时可能会用到多个codesource,也就是不同的权限集,而只有当这些权限集都拥有对资源的权限时才能获得该资源,所以引入了AccessController.doPrivileged来打破这一局限性。
谁来管理权限,权限又如何更改:每个类在被jvm加载时都会指定一个保护域定义了拥有的权限,可以通过制定自定义的java.policy文件来添加需要的权限。
1.2 BIO的缺陷和适用场景
缺陷:虽然可以使用线程池的方式进行优化,但是每有一个请求进来就需要开启一个线程,容易浪费资源,并且BIO是阻塞式的,阻塞操作体现在处理线程在数据没准备好的时候一直等待。
适用场景:在连接数不多的情况下,连接需要持续传送信息可能使用BIO更加适合。
2 NIO
2.1 NIO解决的问题以及解决方式
在BIO阶段所存在的问题就是当一个请求进来的时候就会尝试去读取数据,但是数据没准备好就会进入阻塞,这样的无效等待浪费资源。而NIO解决这一问题的方式就是将多个无效等待变成一个无效等待,讲建立连接和读取数据放到同一层处理,这样就不会在建立连接之后一直等待对方发送数据,而是在对方有数据的时候进行通知,服务端进行接受,从阻塞式变成了非阻塞式。(tips:同步异步关注点是你问内核数据有没有准备好,还是内核主动通知你数据有没有准备好。阻塞非阻塞关注点时你的处理线程在数据没有准备好的时候是一直在等待状态还是可以去做其他的事情。)
2.2 NIO传递信息与BIO的不同点
NIO的传输是基于缓冲区,而BIO的传输是基于流的,基于流的传输灵活性太低无法前后移动数据,而基于缓冲区的传输可以重复读取更加灵活,并且NIO中的通道是双向的不同于流的单向。
2.3 NIO的缺点和使用场景
缺点:使用一个单线程管理多个通道,在解析数据方面可能会比较繁琐
适用场景:在连接数较多,但是每次只发送少量数据,例如简单的聊天室这种使用NIO可能更加合适
3 Netty
3.1 Netty解决了什么问题
netty其实算是对NIO进行了补充,把复杂api进行包装并且加上了多线程的使得不需要自己去处理这方面的问题,并且增加了可靠性在断连重连、网络闪断、半包读写、失败缓存、网络拥塞和异常码流方面都做了处理。
3.2 Netty的线程模型
三种Reactor模型:
- 单线程模型类似于BIO强调一个线程处理所有事物
- 多线程模型类似于NIO使用一个线程监听端口,其他线程处理IO请求
- 主从多线程强调监听端口的是一个线程池而不是单个线程,并且accept线程不处理IO之前的事务了,而是把这些操作下放其他线程,本身专注于监听认证以及过滤,所以就有一个针对accept线程的主从概念。
netty的IO模型:采用类似于主从多线程模型的方式,acepter部分分为mainreactor和subreactor来进行,并且分为两个线程池,一个为mainreactor使用,一个为subreactor和woker使用。
3.3 Netty的基础组件以及各自的作用
- Bootstrap or ServerBootstrap:用来配置程序以及处理的方式等
- EventLoop,EventLoopGroup:EventLoop代表处理请求以及处理io的对象,eventloopgroup代表一个线程池,分成两个主从线程池。
- Channel,ChannelInitializer,ChannelPipeline:Channel用来定义与客户端连接时使用的类型一般为NioServerSocketChanne,在initializer中对channel中输入的事件选择相应的处理器进行处理,并且放入 ChannelPipeline中。
- ChannelHandler:用于处理channel中的事件,并且有三个子类用于对特定事件进行处理,分别的Channel(In/out/Duplex)boundHandlerAdapter
- ChannelFuture:由于netty中io操作是异步的所以注册一个监听,当事件处理完成就能对返回的结果进行操作
3.4 Netty能用来干什么,适用什么场景
Netty能用来干什么取决于我们使用netty来干嘛,因为Netty本质上只是一个对于通信的包装,当我们对端与端之间的通信操作熟练之后可以设计自己的协议编写自己的简易版RPC框架,同时也能编写提供不同服务的服务器。