一、BIO
1、单线程模式(服务端)
while(true) {
accept();
...
read();
}
- 阻塞在accept(),接受客户端的socket连接;
- 如果有客户端响应,然后就会阻塞在read,等待客户端发送数据;
- 如果客户端有数据发送,然后回到accept(),继续处理下一个客户端
缺点:只能阻塞处理客户端的请求,如果第一个客户端一直没有数据发送过来,那么会一只阻塞等待客户端发送数据,当下一个客户端来请求了,也不会响应,这样的话,就会处理客户端请求特别慢
2、多线程模式(服务端) - 基于上面的缺点,我们可以把阻塞读取客户端的数据,放在另外一个线程中做,这样服务端就不会阻塞在read()
注意:这样还是会有缺陷,如果现在有10万、20万的用户请求,那么对应我服务端就得创建10万、20万个线程,这种开销对于服务端来说,就太大了
---------所以出现了NIO----------
二、NIO
服务端接受到socket连接后,将其放在一个队列中,并为每个socket设置有就绪事件发生的回调函数,当有数据发送过来以后,就会触发这个回调函数,我用另外一个线程去处理这些就绪事件,并为每个就绪事件创建一个线程处理和响应客户端。
java中的NIO有两种实现模式,一个是select、一个是epoll。
三、select 和 epoll的区别
- select
当有就绪事件发生时,select返回的是所有的描述符,其中包括有就绪事件的和没有就绪事件的,这个时候呢,我就得去挨个遍历每个描述符,并判定是否有就绪事件发生。
- epoll
当有就绪事件发生时,epoll返回的描述符都是有就绪事件的描述符,这样比起select就少了很多对描述符的遍历