《netty权威指南》读书笔记

一、BIO

1、服务端程序:

 package bio;

 import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date; public class BioServer { public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8081);
Socket clientSocket = null;
while(true){
clientSocket = serverSocket.accept();//如果没有客户端接入,主线程阻塞在这里
new Thread(new ServerHandler(clientSocket)).start();
}
//finall关闭serverSocket
} } class ServerHandler implements Runnable{
private Socket clientSocket; public ServerHandler(Socket clientSocket) {
this.clientSocket = clientSocket;
} @Override
public void run() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
PrintWriter writer = new PrintWriter(this.clientSocket.getOutputStream(), true);
while(true){
String body = reader.readLine();
if (body==null){
break;
}
System.out.println(body);
writer.println(new Date().toString() + "->" + body);
}
} catch (IOException e) {
e.printStackTrace();
}
//finally关闭资源:流和socket
}
}
  • 服务端使用8081端口打开服务,不断接入客户端请求,每接入一个请求,都创建一个线程来处理这个请求。
  • 处理逻辑:读取客户端传来的信息,之后想客户端写信息。

2、客户端程序:

 package bio;

 import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket; public class BioClient {
public static void main(String[] args) throws IOException {
Socket clientSocket = new Socket("127.0.0.1", 8081);
BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true);
writer.println("haha");
String resp = reader.readLine();
System.out.println(resp);
//finall关闭serverSocket
}
}
  • 客户端创建socket去连接服务端,之后想服务端写信息,并且读取服务端传来的信息。

服务端阻塞的几个点:

  • serverSocket.accept();//如果没有客户端接入,主线程阻塞在这里
  • 输入流InputStream的read操作也会阻塞:直到“有数据可读”或者“可用数据读取完毕”或者“发生异常”
  • 输出流OutputStream的write操作也会阻塞:直到“所有要发送的字节全部写入”或者“发生异常”

二、NIO

1、服务端程序

 package nio;

 import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator; public class NioServer {
public static void main(String[] args) throws IOException {
Selector selector = Selector.open(); ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.socket().bind(new InetSocketAddress(8083));//监听链接8082端口的客户端socket
serverChannel.register(selector, SelectionKey.OP_ACCEPT);//将serverChannel注册到selector,并监听接受连接事件 while (selector.select() > 0) {//该方法会发生阻塞,直到至少有一个事件"准备就绪"为止
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey sk = it.next();
if (sk.isAcceptable()) {
SocketChannel clientChannel = serverChannel.accept();//相当于客户端三次握手
clientChannel.configureBlocking(false);
clientChannel.register(selector, SelectionKey.OP_READ);
} else if (sk.isReadable()) {
SocketChannel clientChannel = (SocketChannel) sk.channel();
ByteBuffer buf = ByteBuffer.allocate(1024);
while (clientChannel.read(buf) > 0) {//将通道中的数据读到缓冲区,因为clientChannel已经是非阻塞的,所以这里的read是非阻塞的
buf.flip();//将缓冲区由写模式切换到读模式
byte[] bytes = new byte[buf.remaining()];
buf.get(bytes);//将缓冲区中的数据读取到bytes中
String body = new String(bytes, "UTF-8");
System.out.println("接收到来自客户端的信息:" + body);
buf.clear();
}
}
it.remove();
}
}
}
}
  • nio三组件:

    • Buffer:用于存取数据,最主要的是ByteBuffer

      • position:下一个将被操作的字节位置
      • limit:在写模式下表示可以进行写的字节数,在读模式下表示可以进行读的字节数
      • capacity:Buffer的大小
    • Channel:用于传输数据,与Buffer相互配合
    • Selector:多路复用器。轮询注册在其上的Channel,当发现某个或者多个Channel处于“就绪状态”后(有新的TCP链接接入、读、写事件),从阻塞状态返回就绪的Channel的SelectionKey集合,之后进行IO操作。
  • selector.select():阻塞,直到有“就绪事件”发生或抛出异常

2、客户端程序

 package nio;

 import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; public class NioClient {
public static void main(String[] args) throws IOException {
SocketChannel clientChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8083));//向服务端发出连接请求,服务端会通过accept()方法实现三次握手后,建立连接
clientChannel.configureBlocking(false);
ByteBuffer buf = ByteBuffer.allocate(1024);//分配在JVM堆中:capacity=1024;position=0;limit=1024
// ByteBuffer buf = ByteBuffer.allocateDirect(1024);//分配在堆外内存(物理内存)中
buf.put("abcde".getBytes());//将数据写入缓冲区buf中:capacity=1024;position=5;limit=1024
buf.flip();//将缓冲区从写模式切换到读模式:capacity=1024;position=0;limit=5
clientChannel.write(buf);//将缓冲区的数据写入通道:capacity=1024;position=5;limit=5
buf.clear();//清空缓冲区:capacity=1024;position=0;limit=1024
clientChannel.close();
}
}

附:ByteBuffer使用JVM堆内存和使用堆外内存的区别:(图片来自尚硅谷的NIO教程)

  • 使用堆内存:

    • 应用程序将数据写入用户地址空间(JVM)中,之后将用户地址空间中的数据拷贝到内核地址空间(操作系统)
  • 使用堆外内存:
    • 直接在物理内存开辟空间,应用程序直接将数据写入物理内存,之后操作系统将其写入硬盘 - “零拷贝”

三、BIO与NIO的比较

1、线程数

  • BIO:一个客户端连接就要使用一个服务端线程来进行处理

    • 可能会有大量的想爱你成处于休眠状态,只是等待输入或输出(阻塞)
    • 为每个线程分配调用栈,大约1M,服务端内存吃紧
    • 即使服务端内存很大,线程数太大会导致线程上下文切换浪费大量时间
  • NIO:一个服务端线程操作一个Selector,就可以处理成千上万的客户端连接

2、阻塞情况

  • BIO:读、写、接受连接都会发生阻塞
  • NIO:只有Selector.select()会阻塞,其实是等待Channel上的“就绪事件”

3、面向对象

  • BIO:面向流
  • NIO:面向Buffer

4、适合点

  • BIO:如果你有少量的连接使用非常高的带宽,一次发送大量的数据,也许典型的IO服务器实现可能非常契合
  • NIO:如果需要管理同时打开的成千上万个连接,这些连接每次只是发送少量的数据,例如聊天服务器,实现NIO的服务器可能是一个优势。

四、Reactor模型

主从模型:

  • 主线程池:

    • 全部由NIO线程组成,使用线程池是因为担心性能问题
    • 接收客户端连接请求,可能包含认证
    • 接收到客户端的连接请求并处理完成(比如认证)后,将创建出来的SocketChannel(查看上边的NIOServer类)注册到次线程池的某一条NIO线程上,之后这条NIO线程进行IO操作。
  • 次线程池:
    • 全部由NIO线程组成
    • 进行IO操作(编解码、业务逻辑等)

第二章 BIO与NIO的更多相关文章

  1. Netty学习--第二章 BIO的模型详解

    一.什么是阻塞.非阻塞.同步.异步 我们以A线程调用B线程的过程例子来讲解这四个概念 在一个程序里,A调用B了,此时如果是 同步: A必须等待B返回结果后,才能继续执行,但是在这期间A会一直监控B的返 ...

  2. 第二章 NIO入门

    传统的同步阻塞式I/O编程 基于NIO的非阻塞编程 基于NIO2.0的异步非阻塞(AIO)编程 为什么要使用NIO编程 为什么选择Netty 第二章 NIO 入门 2.1 传统的BIO编程 2.1.1 ...

  3. 操作系统层面聊聊BIO,NIO和AIO (epoll)

    BIO 有了Block的定义,就可以讨论BIO和NIO了.BIO是Blocking IO的意思.在类似于网络中进行read, write, connect一类的系统调用时会被卡住. 举个例子,当用re ...

  4. Java的BIO和NIO很难懂?用代码实践给你看,再不懂我转行!

    本文原题“从实践角度重新理解BIO和NIO”,原文由Object分享,为了更好的内容表现力,收录时有改动. 1.引言 这段时间自己在看一些Java中BIO和NIO之类的东西,也看了很多博客,发现各种关 ...

  5. 【网络IO系列】IO的五种模型,BIO、NIO、AIO、IO多路复用、 信号驱动IO

    前言 在上一篇文章中,我们了解了操作系统中内核程序和用户程序之间的区别和联系,还提到了内核空间和用户空间,当我们需要读取一条数据的时候,首先需要发请求告诉内核,我需要什么数据,等内核准备好数据之后 , ...

  6. 《深入理解java虚拟机》第二章 Java内存区域与内存溢出异常

    第二章 Java内存区域与内存溢出异常 2.2 运行时数据区域  

  7. 第二章Java内存区域与内存溢出异常

    第二章 Java内存区域与内存溢出异常 一.概述 对与Java程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要为每个new操作去写delete/free代码,不容易出现内存泄露和内存溢出问 题, ...

  8. 从实践角度重新理解BIO和NIO

    前言 这段时间自己在看一些Java中BIO和NIO之类的东西,看了很多博客,发现各种关于NIO的概念说的天花乱坠头头是道,可以说是非常的完整,但是整个看下来之后,自己对NIO还是一知半解的状态,所以这 ...

  9. Java中BIO,NIO,AIO的理解

    在高性能的I/O体系设计中,有几个概念常常会使我们感到迷惑不解.具体如下: 1 什么是同步? 2 什么是异步? 3 什么是阻塞? 4 什么是非阻塞? 5 什么是同步阻塞? 6 什么是同步非阻塞? 7  ...

随机推荐

  1. nodejs备忘总结(一) -- node和express安装与配置,新建简单项目(附安装配置过程中遇到问题的解决方法)

    安装node 本文以安装node_v8.9.0为例(win10环境),下载node-v8.9.0-x64.msi插件 下载后,安装,安装目录默认为C:\Program Files\nodejs 配置环 ...

  2. 外键的约束(Mysql、PostgreSQL)

    关于外键是什么,具体不再详述,可以自行百度. 讲一下关于外键的 On Delete和On Update的使用 最近在项目的表中看到这些,不懂顺便查了查: ONSTRAINT "c_clust ...

  3. 应用通信-方案一:RestTemplate

    @RestController public class ClientController { @Autowired private LoadBalancerClient loadBalancerCl ...

  4. C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped

    节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing). 内存映射文件对于托管世界的开发人员来说似乎很陌生,但它确实已经是很远古的技术了,而且在操作 ...

  5. An Isolated DAC Using PWM Output

    An Isolated DAC Using PWM Output Arduino‘s (ATmega328P) PWM outputs via analogWrite can be convenien ...

  6. THE TOOLS TO MANAGE YOUR DATA ACROSS CLOUDS

    http://blog.grexit.com/manage-data-across-clouds/ That the average small business uses a cloud servi ...

  7. ChromeDriver启动Chrome浏览器后,地址栏只显示data;——chromeDriver版本不对

    ChromeDriver启动Chrome浏览器后,地址栏只显示data; 错误原因: chromeDriver版本不对,不同版本的chromeDriver对应不同版本的chrome浏览器 chrome ...

  8. code.google.com/p/log4go 下载失败

    用 glide 下载 goim 的依赖包时报错,提示: code.google.com/p/log4go 找不到,即下载失败 主要是 code.google.com 网站已关闭导致的, 有人把它 fo ...

  9. centos安装tomcat7

    转自:http://www.cnblogs.com/sixiweb/archive/2012/11/26/2789458.html 安装tomcat7: tomcat7下载主页: http://tom ...

  10. go标准库DOC与 raft

    http://studygolang.com/static/pkgdoc/index.html https://github.com/avelino/awesome-go#database