网络模型BIO/NIO

BIO

BIO是传统的同步阻塞IO。对于一次读取IO的操作,数据并不会直接拷贝到程序缓冲区。通常包括两个不同阶段:

  • 等待数据准备好,到达内核缓冲区
  • 从内核向进程复制数据。

对于一个套接字上的输入操作,第一步通常涉及等待数据从网络中到达,当所有等待分组到达时,它被复制到内核中的某个缓冲区。第二步就是把数据从内核缓冲区复制到应用程序缓冲区。

应用进程:负责收取消息
若数据没准备好,会一直阻塞。
来一个用户,起一个线程。

缺点:

  • 同步阻塞接收数据的方式比较低效
  • 这种客户端和线程1:1的模式比较消耗资源,如果客户端较多则服务器承受不住压力。

NIO

NIO即I/O复用模型,是同步非阻塞模型。

NIO原理:应用进程去内核调用数据,用selector去帮助应用进程监听内核,如果数据准备好了,selector会通知应用进程有数据了,然后应用进程再去读取数据。

NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。

NIO包括三大组件:

  • selector(多路复用器)
  • channel(通道)
  • buffer(缓冲区)

selector

NIO模型的核心,用来监听内核。
Selector与Channel是相互配合使用的,这些channel需要我们通过代码手动的注册到selector上,但此时Channel必须为非阻塞模式

然后selector会监听所有的channel,一旦有事件发生,selector会通知用户,用户会根据监听到的事件类型做出不同的处理,

Selector可以监听Channel的四种状态(Connect、Accept、Read、Write),当监听到某一Channel的某个状态时,才允许对Channel进行相应的操作。

  • Connect:某一个客户端连接成功后
  • Accept:准备好进行连接
  • Read:可读
  • Write:可写

channel

传统IO操作对read()或write()方法的调用,可能会因为没有数据可读/可写而阻塞,直到有数据响应。也就是说读写数据的IO调用,可能会无限期的阻塞等待,效率依赖网络传输的速度。最重要的是在调用一个方法前,无法知道是否会被阻塞。

NIO的Channel抽象了一个重要特征就是可以通过配置它的阻塞行为,来实现非阻塞式的通道。

serverSocketChannel.configureBlocking(false);//设置为非阻塞模式

Channel是一个双向通道,与传统IO操作只允许单向的读写不同的是,NIO的Channel允许在一个通道上进行读和写的操作。

客户端 服务器 都会对应一个自己的channel,并且这个channel是唯一的。

  • 与用户IO连接,通过channel就可以进行读写操作。可以监听到什么时候进行了读操作,写操作。
  • 与用户socket也连接,所以只要监听channel,就能监听到客户端或服务器发生的所有事件。
  • 并且我们可以直接使用channel进行消息的发送,也可以直接使用channel进行连接的建立。

buffer

channel在发送数据的时候不能直接将数据本身进行发送,需要将数据放在buffer中,进行传输。
buffer–类似于数组,是NIO模型提供的一种数据结构,便于我们操作。

channel和buffer之间的关系:
在这里插入图片描述buffer的分配:
对buffer对象的操作首先进行分配,buffer提供一个allocate(int capacity)方法分配一个指定字节大小的对象。
向buffer中写数据:

  • 从channel写到buffer
int bytes = channel.read(buf); //将channel中的数据读取到buf中

  • 通过put方法写到buffer
buf.put(byte); //将数据通过put()方法写入到buf中

flip()方法:
将Buffer从写模式切换到读模式,调用flip()方法会将position设置为0,并将limit设置为之前的position的值。

sendBuffer.clear();//每次要清空
SocketChannel client = (SocketChannel) selectionKey.channel();
String sendMsg = "Server recv hello";
sendBuffer.put(sendMsg.getBytes());//将信息放入buffer
sendBuffer.flip();//put后标志位发生改变,要将其移至首部

从buffer中读数据

  • 从buffer读取数据到channel
 client.write(sendBuffer);//将channel数据写入buffer中
  • 通过buffer的get方法读取数据
byte bt = buf.get(); //从buf中读取一个byte

NIO优点

  • 通过Channel注册到Selector上的状态来实现一种客户端与服务端的通信。
  • Channel中数据的读取是通过Buffer , 一种非阻塞的读取方式。
  • Selector 多路复用器 单线程模型, 线程的资源开销相对比较小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值