一、 BIO和 NIO 的区别

1、BIO的工作流程

1.1操作系统的 2 个空间

名称 简单介绍
内核空间 32 位 4G 内存的系统中,1G 位内核空间,此空间存放核心指令等操作,按运行特权 Ring0 来操作,执行时,称为运行在内核态。操作如:磁盘读写、内存管理、网络通讯等
用户空间 用户运行的程序等,在用户空间执行命令,受到系统限制。可在用户态与内核态间切换(调用本地方法、系统操作等)。

1.2 阻塞式

image.png

1.3 stream

enter image description here

1.4 socket编程

image.png

基于以上介绍,我们可以简单总结得以下结论:

  • BIO模式下应用向内核请求数据(从准备到拷贝)全程阻塞,应用只能干等直到请求完成。
  • BIO模式下是面向流的 I/O,这意味着我们需要从流中以先进先出的方式单向读取一个或多个字节,直至读取所有字节。
  • BIO模式下的服务端接收到客户端请求需要创建一个新的线程,线程创建、切换、销毁耗费了大量资源。

2、NIO的工作流程

2.1 多路复用

image.png

2.1 Selector

image.png

2.2 channel


基于以上介绍,我们可以简单总结得以下结论:

  • 与 BIO 的区别在于 BIO 内每个请求将新建线程,而此处可复用已使用完成的资源,使用单个或少量线程循环处理请求。
  • 与 BIO 的Stream 区别在于Channel ,我们可以从它读取数据,也可以向它写入数据。它是双向且非阻塞的。

3、 小结

NIO 和 BIO 的区别主要体现在三个方面:

image.png

其中,选择器( Selector )是 NIO 能实现非阻塞的基础。

二、 mina的工作原理

image.png

NioSocketAcceptor acceptor=new NioSocketAcceptor();//默认创建CPU核数+1个线程
……
……
acceptor.bind(new InetSocketAddress(PORT));
  • 当 IoService 实例创建的同时,IoProcessor 池、线程池也被创建好了。
  • 当 IoService 建立套接字(IoAcceptor 的bind()或者是IoConnector 的connect()方法被调用)时,IoService 从线程池中取出一个线程,监听套接字端口;
  • 当 IoService 监听到套接字上有连接请求时,建立IoSession 对象,从IoProcessor池中取出一个IoProcessor 实例执行这个会话通道上的过滤器、IoHandler;
  • 需要对上图说明的当 IoService 建立套接字时,IoService 是从线程池中取出一个线程,而不是创建了一个新的线程;

image.png
此图并没有对channel的工作方式进行详细的说明,大概能说明的是怎么通过selector管理不同的事件。
image.png
image.png
image.png
从另外一个角度描述线程的工作方式,遗憾的是没有进一步对selector层描绘。需要说明的是,每个Porcessor线程中都维护着一个selector,对它维护的IoSession集合进行进行select,然后对select的结果进行遍历。这样做充分利用多核的优势,提高了并发处理的能力。
1、如何配置IoProcessor 的多线程工作方式?
2、IoAcceptor和selector是一对一还是一对多?

三、 编解码

1、 编码的方法

定长、定界符、自定义协议包
A、
定长的方式:abc,123456等类似的通信方式;例如100字节,如果不够,使用空格补齐。这种方案最大的限制是,消息的长度不能超过限制。
B、
定界符:helloworld|jack|….|…. 通过特殊的符号来区别消息。前面demo使用的LineDelimeter.WINDOWS.getValue();在遇到字符\n、\r\n的时候,就认为是一个完整的数据包。
这样方式会出现粘包、半包等现象。
如:因为网络通信的原因,接收信息如下
Hello world|jack 123|带来了不正确消息,这样就应该丢弃数据。
C、
自定义协议包


Nirvana
32 声望5 粉丝

整个体系复杂对我而言又陌生,每次学习对自己的脑力与知识体系都是一个巨大的挑战,也需要克服巨大的惰性;巨大的挑战同时也意味着巨大的诱惑。意味着我搞懂了,就能超越平凡的大多数,能力又上升了一个台阶。一...