《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. oracle批量插入優化方案

    今天聽DBA説如果從一個表批量查詢出一批數據之後批量插入另外一張表的優化方案: 1)不寫歸檔日誌: 2)採用獨佔 關於insert /*+ append */我們需要注意以下三點: a.非歸檔模式下, ...

  2. Unity3D导入MAX文件的一些问题(zz)

    1.轴向偏转 MAX模型导入Unity3D后,X轴会自动偏转-90度.是因为Unity3D采用的是左手坐标系,而3DMax采用的是右手坐标系.无奈啊,这是很多游戏引擎跟Max结合后都会产生的问题.兼容 ...

  3. GDI 泄漏检测方法

    方法一 1.打开电脑的[任务管理器],选择[进程]页,点击菜单项的[查看]项,选择[选择列]: 2.勾选[GDI对象(J)]即可. 3.此时,用户就可以在进程中看到每个进程对应的GDI对象,每个进程的 ...

  4. Codeforces Round #397 by Kaspersky Lab and Barcelona Bootcamp (Div. 1 + Div. 2 combined) D. Artsem and Saunders 数学 构造

    D. Artsem and Saunders 题目连接: http://codeforces.com/contest/765/problem/D Description Artsem has a fr ...

  5. Java+Windows+ffmpeg实现视频转换

    最近由于项目需要,研究了一下如何用Java实现视频转换,“着实”废了点心思,整理整理,写出给自己备忘下. 思路 由于之前没有没法过相关功能的经验,一开始来真不知道从哪里入手.当然,这个解决,googl ...

  6. Serilog简介

    Serilog是.net 下的新兴的日志框架,本文这里简单的介绍一下它的用法. 首先安装Nuget包: Install-Package Serilog Install-Package Serilog. ...

  7. .net core下的dotnet全局工具

    .net core 2.1后支持了一个全新的部署和扩展命令,可以自己注册全局命令行. dotnet install tool -g dotnetsaydotnetsay 也可以自己构建自己的命令行,一 ...

  8. Git 的 WindowsXP安装

    文章1: http://blog.sina.com.cn/s/blog_5063e4c80100sqzq.html 一.安装必要客户端 1. TortoiseGit http://tortoisegi ...

  9. C#中如何选择使用T[]或List<T>

    当有一组数据需要存放,到底是使用T[]呢,还是选择List<T>呢? 先来看数组. 所有的数组类型都隐式地从System.Array这个抽象类派生,而System.Array又派生自Sys ...

  10. TXMLDocument use case (Delphi)

    Description This example illustrates the basic operations on an XML document. Code procedure CreateD ...