通天战队|「015期」JavaSE面试题(十五):网络IO流( 三 )


public class AIOServer {public final static int PORT = 9888;private AsynchronousServerSocketChannel server;public AIOServer throws IOException {server = AsynchronousServerSocketChannel.open.bind(new InetSocketAddress(PORT));}public void startWithFuture throws InterruptedException,ExecutionException, TimeoutException {while (true) {// 循环接收客户端请求Future future = server.accept;AsynchronousSocketChannel socket = future.get;// get 是为了确保 accept 到一个连接handleWithFuture(socket);}}public void handleWithFuture(AsynchronousSocketChannel channel) throws InterruptedException, ExecutionException, TimeoutException {ByteBuffer readBuf = ByteBuffer.allocate(2);readBuf.clear;while (true) {// 一次可能读不完//get 是为了确保 read 完成 , 超时时间可以有效避免DOS攻击 , 如果客户端一直不发送数据 , 则进行超时处理Integer integer = channel.read(readBuf).get(10, TimeUnit.SECONDS);System.out.println("read: " + integer);if (integer == -1) {break;}readBuf.flip;System.out.println("received: " + Charset.forName("UTF-8").decode(readBuf));readBuf.clear;}}public void startWithCompletionHandler throws InterruptedException,ExecutionException, TimeoutException {server.accept(,new CompletionHandler {public voidcompleted(AsynchronousSocketChannel result, Object attachment) {server.accept(, this);// 再此接收客户端连接handleWithCompletionHandler(result);}@Overridepublic voidfailed(Throwable exc, Object attachment) {exc.printStackTrace;}});}public voidhandleWithCompletionHandler(final AsynchronousSocketChannel channel) {try {final ByteBuffer buffer = ByteBuffer.allocate(4);final long timeout = 10L;channel.read(buffer, timeout, TimeUnit.SECONDS, , new CompletionHandler {@Overridepublic voidcompleted(Integer result, Object attachment) {System.out.println("read:" + result);if (result == -1) {try {channel.close;} catch (IOException e) {e.printStackTrace;}return;}buffer.flip;System.out.println("received message:" + Charset.forName("UTF-8").decode(buffer));buffer.clear;channel.read(buffer, timeout, TimeUnit.SECONDS, , this);}@Overridepublic voidfailed(Throwable exc, Object attachment) {exc.printStackTrace;}});} catch (Exception e) {e.printStackTrace;}}public static void main(String args[]) throws Exception {// new AIOServer.startWithFuture;new AIOServer.startWithCompletionHandler;Thread.sleep(100000);}}Q:
什么是epoll?
把一个磁盘文件映射到内存里来 , 然后把映射到内存里来的数据通过socket发送出去。
有一种mmap技术 , 也就是内存映射 , 直接将磁盘文件数据映射到内核缓冲区 , 这个映射的过程是基于DMA引擎拷贝的 , 同时用户缓冲区是跟内核缓冲区共享一块映射数据的 , 建立共享映射之后 , 就不需要从内核缓冲区拷贝到用户缓冲区了 。
光是这一点 , 就可以避免一次拷贝 , 但是这个过程中还是会用户态切换到内核态去进行映射拷贝 , 接着再次从内核态切换到用户态 ,建立用户缓冲区和内核缓冲区的映射,
接着把数据通过Socket发送出去 , 还是要再次切换到内核态,
接着直接把内核缓冲区里的数据拷贝到Socket缓冲区里去 , 然后再拷贝到网络协议引擎里 , 发送出去就可以了 , 最后切换回用户态。
减少一次拷贝 , 但是并不减少切换次数 , 一共是4次切换 , 3次拷贝


推荐阅读