什么是bio

同步阻塞式IO,服务端创建一个ServerSocket,然后客户端用一个Socket去连接那个ServerSocket,然后ServerSocket接收到一个Socket的连接请求就创建一个Socket和一个线程去跟那个Socket进行通信。

public class BioServer {

public static void main(String[] args) {

// 服务端开启一个端口进行监听

int port = 8080;

ServerSocket serverSocket = null; //服务端

Socket socket; //客户端

InputStream in = null;

OutputStream out = null;

try {

serverSocket = new ServerSocket(port); //通过构造函数创建ServerSocket,指定监听端口,如果端口合法且空闲,服务器就会监听成功

// 通过无限循环监听客户端连接,如果没有客户端接入,则会阻塞在accept操作

while (true) {

System.out.println("Waiting for a new Socket to establish" + " ," + new Date().toString());

socket = serverSocket.accept();//阻塞 三次握手

in = socket.getInputStream();

byte[] buffer = new byte[1024];

int length = 0;

while ((length = in.read(buffer)) > 0) {//阻塞

System.out.println("input is:" + new String(buffer, 0, length) + " ," + new Date().toString());

out = socket.getOutputStream();

out.write("success".getBytes());

System.out.println("Server end" + " ," + new Date().toString());

}

}

} catch (Exception e) {

e.printStackTrace();

} finally {

// 必要的清理活动

if (serverSocket != null) {

try {

serverSocket.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if (in != null) {

try {

in.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if (out != null) {

try {

out.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

}

什么是nio

同步非阻塞

包括Selector,这是多路复用器,selector会不断轮询注册的channel,如果某个channel上发生了读写事件,selector就会将这些channel获取出来,我们通过SelectionKey获取有读写事件的channel,就可以进行IO操作。一个Selector就通过一个线程,就可以轮询成千上万的channel,这就意味着你的服务端可以接入成千上万的客户端。

public class NioDemo implements Runnable {

public int id = 100001;

public int bufferSize = 2048;

@Override

public void run() {

init();

}

public void init() {

try {

// 创建通道和选择器

ServerSocketChannel socketChannel = ServerSocketChannel.open();

Selector selector = Selector.open();

InetSocketAddress inetSocketAddress = new InetSocketAddress(

InetAddress.getLocalHost(), 4700);

socketChannel.socket().bind(inetSocketAddress);

// 设置通道非阻塞 绑定选择器

socketChannel.configureBlocking(false);

socketChannel.register(selector, SelectionKey.OP_ACCEPT).attach(

id++);

System.out.println("Server started .... port:4700");

listener(selector);

} catch (Exception e) {

}

}

public void listener(Selector in_selector) {

try {

while (true) {

Thread.sleep(1 * 1000);

in_selector.select(); // 阻塞 直到有就绪事件为止

Set readySelectionKey = in_selector

.selectedKeys();

Iterator it = readySelectionKey.iterator();

while (it.hasNext()) {

SelectionKey selectionKey = it.next();

// 判断是哪个事件

if (selectionKey.isAcceptable()) {// 客户请求连接

System.out.println(selectionKey.attachment()

+ " - 接受请求事件");

// 获取通道 接受连接,

// 设置非阻塞模式(必须),同时需要注册 读写数据的事件,这样有消息触发时才能捕获

ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey

.channel();

serverSocketChannel

.accept()

.configureBlocking(false)

.register(

in_selector,

SelectionKey.OP_READ

| SelectionKey.OP_WRITE).attach(id++);

System.out

.println(selectionKey.attachment() + " - 已连接");

// 下面这种写法是有问题的 不应该在serverSocketChannel上面注册

/*

* serverSocketChannel.configureBlocking(false);

* serverSocketChannel.register(in_selector,

* SelectionKey.OP_READ);

* serverSocketChannel.register(in_selector,

* SelectionKey.OP_WRITE);

*/

}

if (selectionKey.isReadable()) {// 读数据

System.out.println(selectionKey.attachment()

+ " - 读数据事件");

SocketChannel clientChannel = (SocketChannel) selectionKey.channel();

ByteBuffer receiveBuf = ByteBuffer.allocate(bufferSize);

clientChannel.read(receiveBuf);

System.out.println(selectionKey.attachment()

+ " - 读取数据:" + getString(receiveBuf));

}

if (selectionKey.isWritable()) {// 写数据

System.out.println(selectionKey.attachment()

+ " - 写数据事件");

SocketChannel clientChannel = (SocketChannel) selectionKey.channel();

ByteBuffer sendBuf = ByteBuffer.allocate(bufferSize);

String sendText = "hello\n";

sendBuf.put(sendText.getBytes());

sendBuf.flip(); //写完数据后调用此方法

clientChannel.write(sendBuf);

}

if (selectionKey.isConnectable()) {

System.out.println(selectionKey.attachment()

+ " - 连接事件");

}

// 必须removed 否则会继续存在,下一次循环还会进来,

// 注意removed 的位置,针对一个.next() remove一次

it.remove();

}

}

} catch (Exception e) {

System.out.println("Error - " + e.getMessage());

e.printStackTrace();

}

}

/**

* ByteBuffer 转换 String

*

* @param buffer

* @return

*/

public static String getString(ByteBuffer buffer) {

String string = "";

try {

for (int i = 0; i < buffer.position(); i++) {

string += (char) buffer.get(i);

}

return string;

} catch (Exception ex) {

ex.printStackTrace();

return "";

}

}

}

什么是aio

异步非阻塞

每个连接发送过来的请求,都会绑定一个buffer,然后通知操作系统去异步完成读,此时你的程序是会去干别的事儿的,等操作系统完成数据读取之后,就会回调你的接口,给你操作系统异步读完的数据。

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(null,

new CompletionHandler() {

public void completed(AsynchronousSocketChannel result, Object attachment) {

server.accept(null, this);// 再此接收客户端连接

handleWithCompletionHandler(result);

}

@Override

public void failed(Throwable exc, Object attachment) {

exc.printStackTrace();

}

});

}

public void handleWithCompletionHandler(final AsynchronousSocketChannel channel) {

try {

final ByteBuffer buffer = ByteBuffer.allocate(4);

final long timeout = 10L;

channel.read(buffer, timeout, TimeUnit.SECONDS, null, new CompletionHandler() {

@Override

public void completed(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, null, this);

}

@Override

public void failed(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);

}

}

什么是epoll

一种多路复用的技术,可以解决之前poll和select大量并发连接情况下cpu利用率过高,以及需要遍历整个被侦听的描述符集的问题。epoll只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。

什么是mmap技术

把一个磁盘文件映射到内存里来,然后把映射到内存里来的数据通过socket发送出去

有一种mmap技术,也就是内存映射,直接将磁盘文件数据映射到内核缓冲区,这个映射的过程是基于DMA引擎拷贝的,同时用户缓 冲区是跟内核缓冲区共享一块映射数据的,建立共享映射之后,就不需要从内核缓冲区拷贝到用户缓冲区了

光是这一点,就可以避免一次拷贝了,但是这个过程中还是会用户态切换到内核态去进行映射拷贝,接着再次从内核态切换到用户态, 建立用户缓冲区和内核缓冲区的映射

接着把数据通过Socket发送出去,还是要再次切换到内核态

接着直接把内核缓冲区里的数据拷贝到Socket缓冲区里去,然后再拷贝到网络协议引擎里,发送出去就可以了,最后切换回用户态

减少一次拷贝,但是并不减少切换次数,一共是4次切换,3次拷贝

什么是零拷贝技术

linux提供了sendfile,也就是零拷贝技术

这个零拷贝技术,就是先从用户态切换到内核态,在内核态的状态下,把磁盘上的数据拷贝到内核缓冲区,同时从内核缓冲区拷贝一些 offset和length到Socket缓冲区;接着从内核态切换到用户态,从内核缓冲区直接把数据拷贝到网络协议引擎里去

同时从Socket缓冲区里拷贝一些offset和length到网络协议引擎里去,但是这个offset和length的量很少,几乎可以忽略

只要2次切换,2次拷贝,就可以了

说一下select,poll,epoll的区别?

select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。

epoll也需要调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是回调机制带来的性能提升。

select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current往设备等待队列中挂一次,而epoll只要一次拷贝,而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内部定义的等待队列)。这也能节省不少的开销。

java 网络 io流_【015期】JavaSE面试题(十五):网络IO流相关推荐

  1. 第十五章 IO流(转换流 字符流 字符缓冲流 打印流)

    Java基础15 第十五章 IO流(转换流 字符流 字符缓冲流 打印流) 15.1 字符编码和字符集 15.1.1 字符编码 15.1.2 字符集 15.1.3 String类getBytes()方法 ...

  2. 诗词在线网络月刊2010年第二期(总第十四期)

    http://www.chinapoesy.com/yuekan2010021.html 诗词在线网络月刊2010年第二期(总第十四期) 2010年2月份的月刊终于与大家见面了:),诗歌由会员自荐,经 ...

  3. JAVASE基础模块十五(StringBuffer类)

    JAVASE基础模块十五(StringBuffer类) public class Stbuffer { public static void main(String[] args) { //总共创建五 ...

  4. 网络云存储技术Windows server 2012 (项目十五 存储服务间的数据同步)

    网络云存储技术Windows server 2012 (项目十五 存储服务间的数据同步) 目录 前言 一.项目背景 二. 项目实训题 前言 网络存储技术,是以互联网为载体实现数据的传输与存储,它采用面 ...

  5. Java基础(十五)IO流---字符流(Reader、Writer)、字节流(InputStream、OutputStream)

    IO流(应用广泛) 1.概念与三要素 本质是一套用于数据传输的机制 分类: 根据传输的方向(参照物–内存) 输入流:往内存传输数据 输出流:从内存往外传输数据 根据数据传输方式: 字符流:底层以字符形 ...

  6. 十五、IO流【黑马JavaSE笔记】(本文文中记录了个人学习感受)

    文章目录 IO流 (一)File 1.File类的概述和构造方法 2.File类的创建功能 3.File类判断和获取功能 4.File类的删除功能 5.递归 6.案例(递归求阶乘) 7.案例(遍历目录 ...

  7. sentinel限流_微服务架构进阶:Sentinel实现服务限流、熔断与降级

    摘要 Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案,Sentinel 作为其核心组件之一,具有熔断与限流等一系列服务保护功能,本文将对其用法进行详细介绍. Senti ...

  8. 一个软件网络连接异常_手机也能玩PC大作了,串流软件Steam Link登陆iOS App Store...

    去年V社发布消息宣布,将会推出一款全新的针对智能手机的Steam串流APP,而在近日这个名为Steam Link App终于正式登陆了iOS App Store.玩家可以通过手机和电脑连接,畅玩电脑上 ...

  9. java不想出差_您不想错过的十大Java书籍

    java不想出差 我们通过阅读书籍并进行实验来学习. 因此,必须选择最佳的可用选项. 在本文中,我想与一些书分享我的经验,以及它们如何帮助您发展成为Java开发人员. 让我们从头开始,对于任何Java ...

  10. Java真的不难(二十五)Stream流

    Stream流 上篇文章讲了Java 8 的一个新特性:Lambda表达式,在业务中若能熟练的使用,可以节省很多代码量,看着也整洁很多.那么这篇文章将介绍另一个新特性:Stream流,不要看错哈!!! ...

最新文章

  1. C++成员变量指针和成员函数指针【The semantics of funcitons】
  2. FreeBSD下安装配置Hadoop集群(三)
  3. 史上最全29个自我管理工具!
  4. mysql键1键2_详解mysql基本操作详细(二)
  5. 代码 拉取_Git 利用 Webhooks 实现代码的自动拉取
  6. 小不咖啡——自己写着玩的网站
  7. Spring Boot(九)Swagger2自动生成接口文档和Mock模拟数据
  8. android拍照功能编程,android实现手机App实现拍照功能示例
  9. 【java学习之路】(java SE篇)(练习)关于常用类的心血来潮小练习
  10. Android获取手机屏幕宽高
  11. Chrome DevTools
  12. python合并两个数据框_python-3.x - 如何使用匹配索引合并两个数据框? - SO中文参考 - www.soinside.com...
  13. Scala的那些匿名函数
  14. 一线算法工程师总结:python常用数据挖掘算法PDF版
  15. star法则 java_STAR法则(示例代码)
  16. 执行SOA ——SOA实践指南
  17. Java ThreadFactory接口用法
  18. 如何比较两个json
  19. 案例 :手把手教你运用深度学习构建视频人脸识别模型(Python实现)
  20. 使用超级计算机计算任务是一种什么样的体验?

热门文章

  1. Visual Leak Detector 帮助检查内存泄露
  2. Python-OpenCV 杂项(二): 鼠标事件
  3. Java虚拟机详解----JVM常见问题总结
  4. OpenCV中SUFR、SIFT无法使用的原因及解决办法
  5. 代码之谜(一)- 有限与无限
  6. 压缩跟踪Compressive Tracking
  7. 主成分分析(Principal components analysis)-最大方差解释
  8. 高斯分布绘图的一些记录
  9. linux下如何实现mysql数据库每天自动备份定时备份
  10. OpenCV人脸识别Eigen算法源码分析