分布式中间件基础序言

BIO

  • BIO:blocking io,阻塞等待
  • 例如:创建一个server后,将等待client的连接到来,程序不会向下执行。当连接建立后,触发server去读取client信息。在read client的发送的信息的时候,同样是阻塞的。未拿到client的信息,依然不会进行继续执行。
  • 缺点:无法处理多个client的连接
    -> 对read client data新开一个线程,使得其可以连接多个client,但开销过大,CPU无法支撑。
    -> 线程池:存在上限,若client数据传输过慢等情况,client将长时间占用线程,使得后续client无法获得线程,进行数据传输。同时,被占用的线程被浪费了。

NIO

  • NIO:non-blocking io, 不会阻塞,哪怕没有连接,没有数据传输

多路复用器 selector

  • 案例:
  • 基本思路:常见场景,server端与多个client连接,但只有少部分client在进行数据传输工作。若每次都遍历所有连接,进行数据接受,则会出现s端响应慢,资源浪费等问题。所以,采用集合分别存储 建立的连接 和 数据传输的连接。只对有数据传输的连接进行read数据。
  • 方法:通过selector实现。 —— 等待事件发生,若没有事件发生,就会阻塞(底层不会占用资源)
    对监听的接口,注册一个selector,则当有连接事件到来的时候,会进行处理,并得到一个socketChannel(服务端的)。
    对连接后建立的socketChannel也进行selector注册,并标记注册read事件。则当该channel有read I/O时,会触发该事件,并进行处理。
    在这里插入图片描述
ServerSocketChannel serverSocketChannel = ServerSocketChannel .open();
serverSocketChannel.socket.bind(new InetSocketAddress(9000);
// set to non blocking
serverSocket.configureBlocking(false);
//打开selector,即创建epoll
Selector selector = Selector.open();
//注册到selector上
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

while(true) {
	//等待事件发生
	selector.select();
	//获取selector中注册的全部事件实例
	Set<SelectionKey> selectionKeys = selector.selectedKeys();
	Iterator<SelectionKey> iterator = selectionKeys.iteratior();
	
	while(iterator.hasNext()) {
		SelectionKey key = iterator.next();
		if(key.isAcceptable()) {
			ServerSocketChannel server = (ServerSocketChannel) key.channel();
			SocketChannel socketChannel = server.accept();
			socketChannel.configureBlocking(false);
			socketChannel.register(selector, SelectionKey.OP_READ);
		} else if {key.isReadable()) {
			SocketChannel socketChannel = (SocketChannel)key.channel();
			ByteBuffer byteBuffer = ByteBuffer.allocate(6);
			//read data from channel
			int len = socketChannel.read(byreBuffer);
			//如果数据存在,则进行处理
			if(len > 0) {
				System.out.println("接受数据: " + new String(byteBuffer.array());
			} else if(len == -1){//客户端断开连接
				socketChannel.close();
			}
		}
		//从事件集合中删除本次处理的key,防止下次重复操作
		iterator.remove();
	}
}

selector 底层原理

  • selector实际上是通过epoll实现的,在java中,通过使用Selector.open 可以创建一个epoll实例,步骤如下:
  1. 调用Selector.open()方法 : 返回SelecotorProvider.provider().openSelector();
  2. provider()方法:返回createProvider(“sun.nio.ch.EpollSelectorProvider”);
  3. openSelector()方法:实际上是EpollSelectorProvider对象调用openSelector,该方法将会创建并返回一个EpollSelectorImpl对象
  4. EpollSelectorImpl实现:构建(初始化)时,初始化EpollArrayWrapper,注册的channel放置到该wrapper对象中。
  5. EpollArrayWrapper初始化:其将会调用epollCreate方法,epollCreate()是native方法。
  6. epollCreate方法:调用epoll_create方法,epoll_create是linux的系统函数,用于创建epoll对象。
  • register方法则是将 注册的channel 放入c++层的epoll实例中
  • selector.select则会调用到epoll_ctl epoll_wait等系统函数
epoll
#include <sys / epoll.h>
 
int epoll_ctl(int epfd,int op,int fd,struct epoll_event * event);

该系统调用对文件描述符epfd引用的epoll实例执行控制操作。它要求操作op对目标文件描述符fd执行。

   op参数的有效值为:

   EPOLL_CTL_ADD:在文件描述符epfd所引用的epoll实例上注册目标文件描述符fd,并将事件事件与内部文件链接到fd。

   EPOLL_CTL_MOD:更改与目标文件描述符fd相关联的事件事件。

   EPOLL_CTL_DEL:从epfd引用的epoll实例中删除(注销)目标文件描述符fd。该事件将被忽略,并且可以为NULL(但请参见下面的错误)。

(即op对目标fd进行操作:添加,修改,删除)

epoll_wait,等待epoll文件描述符上的I / O事件。若有事件,则取出,进行响应。若无,则阻塞等待。

#include <sys / epoll.h>
 
int epoll_wait(int epfd,struct epoll_event * events, int maxevents,int timeout);
  • events 指针指向的内存包含对调用者有效的事件。当达到 maxevents 时 epoll_wait() 会返回。maxevents 参数必须大于零
  • 调用等待最长时间是 timeout 毫秒。指针 timeout 为 -1 让 epoll_wait() 无限期地等待,若指定 timeout 为零时即使在没有事件有效 epoll_wait() 也会立即返回(返回值是零)。

从epoll_ctl到epoll_wait列表中,是通过操作系统的中断程序实现的。也即是,利用epoll_ctl注册监控的通路以及关注事件。当这些事件发生时,操作系统的中断程序将把相应的数据和信息放到,epoll_wait中的队列中。再由epoll_wait的队列取出,被上层感知和处理。

select, poll and epoll 三者区别

在这里插入图片描述

  • selector最开始的底层实现是基于 select的,后来演进出了poll,epoll等。
  • select 和poll,都是对所以注册的channel进行遍历,看其是否有事件发生。而epooll则是通过事件通知的机制 实现对事件的监控。

radis线程模型

  • radis是基于epoll实现的
  • 利用epoll_create创建epoll,使用epoll_ctl注册监控同类和关注事件,通过操作系统中断程序完成事件放置到epoll_wait队列中,通过epoll_wait队列获取到事件和相应信息,完成多路复用。
  • 多路复用通俗理解:多条通路,一条线程进行管理。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值