
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实现原理所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)