web----epoll实现原理

web----epoll实现原理,第1张

概述epoll可以用单进程单线程实现高并发 首先我们可以实现单进程单线程实现高并发(模拟非阻塞IO请求) 服务端 //服务端public class BlockNIOServer { public static void main(String[] args) throws IOException, InterruptedException { //获取通道

epoll可以用单进程单线程实现高并发

首先我们可以实现单进程单线程实现高并发(模拟非阻塞IO请求)

服务端

//服务端public class BlockNIOServer {    public static voID main(String[] args) throws IOException,InterruptedException {        //获取通道        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();        //切换非阻塞模式        serverSocketChannel.configureBlocking(false);        //绑定端口        serverSocketChannel.bind(new InetSocketAddress(8090));         //获取选择器        Selector selector = Selector.open();        //将该通道注册到select中,让select监听该通道的连接是否准备就绪        serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);         Iterator<SelectionKey> iterator = null;        //通过选择器轮询获取已经准备就绪的事件        while (selector.select()>0){            iterator = selector.selectedKeys().iterator();            while (iterator.hasNext()){                SelectionKey selectionKey = iterator.next();                //如果获取的是准备连接就绪的事件                if (selectionKey.isAcceptable()){                    System.out.println("有客户端已经准备好连接了....");                    //开始接受连接客户端                    SocketChannel accept = serverSocketChannel.accept();                    //切换非阻塞模式                    accept.configureBlocking(false);                    //将通道注册到selector中,让select监听该通道的数据是否准备就绪                    accept.register(selector,SelectionKey.OP_READ);                }                else if (selectionKey.isReadable()){                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();                    Random random = new Random();                    int i = random.nextInt(100);                    String path = "C:\Users\zhengyan\Desktop\test1\"+i+".txt";                    fileChannel fileChannel = fileChannel.open(Paths.get(path),StandardOpenoption.READ,StandardOpenoption.WRITE,StandardOpenoption.CREATE);                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);                    while (socketChannel.read(byteBuffer)!=-1){                        byteBuffer.flip();                        fileChannel.write(byteBuffer);                        byteBuffer.clear();                    }                    byteBuffer.put("数据已经接受完毕...".getBytes());                    byteBuffer.flip();                    socketChannel.write(byteBuffer);                     fileChannel.close();                    socketChannel.close();                    System.out.println("写入数据成功....");                }                //取消选择键                iterator.remove();            }        }    }}

客户端

//客户端public class BlockNIOClIEnt {    public static voID main(String[] args) throws IOException,InterruptedException {        //获取通道        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",8090));        fileChannel fileChannel = fileChannel.open(Paths.get("C:\Users\zhengyan\Desktop\test1\x.txt"),StandardOpenoption.READ);         //System.out.println("模拟10秒之后发送数据...");        //可以开启两个客户端,一个睡10秒发送数据(先请求),一个不用睡眠(后请求),发现,必须等第一个用户处理完毕之后,第二个用户才可以被处理        //Thread.sleep(20000);         //分配缓冲区大小        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);        //读取本地文件发送到服务器        while (fileChannel.read(byteBuffer)!=-1){            byteBuffer.flip();            socketChannel.write(byteBuffer);            byteBuffer.clear();        }         //告诉服务器,我的数据已经发送完毕        socketChannel.shutdownOutput();        //接受服务器返回来的消息        StringBuffer stringBuffer = new StringBuffer();        int len =-1;        while ((len=socketChannel.read(byteBuffer))!=-1){            byteBuffer.flip();            stringBuffer.append(new String(byteBuffer.array(),len));            byteBuffer.clear();        }        System.out.println(stringBuffer);         socketChannel.close();        fileChannel.close();    }}

假如有三个连接到来了,一个socker通道监听连接是否到来(白色方格),三个socker通道是因为连接到来了,被注册到select中监听数据是否到来(黄色方格),此时select不断的遍历,首先select将其中的一个socker通道(在linux中是fd(int)文件描述符)复制一份到 *** 作系统(这一步是性能的瓶颈所在,让 *** 作提供来看看我这个通道有没有数据到来,或者连接请求的到来),此时 *** 作系统(内核)还会执行别的应用进程,什么执行我们这个检测 *** 作是由 *** 作系统决定(又浪费了一部分时间)。然后一步一步将select选择器中的所有的socket通道全部遍历(select选择器中的socker通道数目越多,性能越差),有的socker通道不活跃,也被检测了,就非常损耗性能。

图中绿色的是select选择器(维护了socker通道),处于应用层,放在用户空间

 

 

epoll

epoll有一段特殊的内存空间( *** 作系统和应用程序共用)

图中绿色的是epoll选择器(维护了socker通道,实现方式是红黑树和链表),处于应用程序和内核共享空间

epoll的第一个优点:不需要额外的复制 *** 作

 

epoll的第一个优点:采用事件通知,取代了之前的轮询(select)

总结

以上是内存溢出为你收集整理的web----epoll实现原理全部内容,希望文章能够帮你解决web----epoll实现原理所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1033838.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-24
下一篇2022-05-24

发表评论

登录后才能评论

评论列表(0条)

    保存