web----epoll实现原理
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(),0,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)
?
轉載于:https://www.cnblogs.com/yanxiaoge/p/11563609.html
總結
以上是生活随笔為你收集整理的web----epoll实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 封装不同类模板的随机数生成器
- 下一篇: python NoSuchElement