【一】五种IO模型:

(1)阻塞IO
(2)非阻塞IO(任务提交,工作线程处理,委托线程等待工作线程处理结果的同时,也可以做其他的事情)
(3)IO复用模型.(委托线程接收多个任务,将任务提交给工作线程。委托线程等待多个工作线程结果,等待到其中一个,处理其中一个具体的工作)
(4)信号驱动模型
(5)异步IO模型

【二】网络编程

(1)网络编程的基本模型:Client/Server模型,也就是两个进程之间进行相互通信。其中服务端提供位置信息(绑定的ip地址和监听的端口号),客户端通过链接操作向服务端监听的地址发起连接请求。通过三次握手建立链接,如果建立链接成功,双方就可以通过网络套接字(Socket)进行通信。

【三】阻塞IO和非阻塞IO的区别
(1)IO的操作:对硬盘的读写、对socket的读写以及外设的读写。
(2)IO读请求操作包括两个 阶段:
    --->查看数据是否就绪;
    --->进行数据拷贝(内核将数据拷贝到用户线程)。
(3)阻塞IO:当用户线程发起一个IO请求操作(本文以读请求操作为例),内核会去查看要读取的数据是 否就绪,对于阻塞IO来说,如果数据没有就绪,则会一直在那等待,直到数据就绪
(4)非阻塞IO:当用户线程发起一个IO请求操作(本文以读请求操作为例),内核会去查看要读取的数据是 否就绪,对于非阻塞IO来说,如果数据没有就绪,则会返回一个标志信息告知用户线 程当前要读的数据没有就绪。当数据就绪之后,便将数据拷贝到用户线程
(5)那么阻塞(blocking IO)和非阻塞(non-blocking IO)的区别就在于第一个阶段,如果数据没有就绪,在查看数据是否就绪的过程中是一直等待,还是直接返回一个标志信息。Java中传统的IO都是阻塞IO,比如通过socket来读数据,调用read()方 法之后,如果数据没有就绪,当前线程就会一直阻塞在read方法调用那里,直到有数据才返回;而如果是非阻塞IO的话,当数据没有就绪,read()方法 应该返回一个标志信息,告知当前线程数据没有就绪,而不是一直在那里等待。

【四】:BIO和NIO

BIO
===>阻塞IO通信,通常导致通信线程被长时间阻塞。
NIO
===>IO多路复用技术
===>非阻塞IO.

【五】:NIO的几个关键的类
(1)缓冲区Buffer
===>Buffer是一个对象,它包含一些要写入或要读出的数据。
===>在NIO的库中,所有数据都是用缓冲区处理的。在读取数据时候,它是直接读到缓冲区中进行的。在写数据时候,写入缓冲区中。任何时候访问NIO中的数据,都是通过缓冲区进行操作。
===>缓冲区实质上是一个数组,通常它是一个字节数组(ByteBuffer),也可以是其他种类的数组。但一个缓冲区不仅仅是一个数组,缓冲区提供了对数据结构化访问以及维护读写位置等信息。
===>ByteBuffer(字节缓冲区),CharBuffer(子符缓冲区),ShortBuffer(短整型缓冲区),IntBuffer(整型缓冲区),LongBuffer(长整型缓冲区),FloatBuffer(浮点型缓冲区),DoubleBuffer(双精度浮点型缓冲区)

(2)通道Channel
===>Channel是一个通道,可以通过它读取和写入数据
===>它就像自来水管一样,网络数据通过Channel读取和写入。
===>通道与流不同之处在于通道是双向的。流只是在一个方向上移动(一个流必须是InputStream或者OutputStream)
===>而且通道可以用于读,写或同时用于读写。
===>Channel分为两大类,分别是用于网络读写的SelectableChannel和用于文件操作的FileChannel
===>NIO网络编程的ServerSocketChannel和SocketChannel都是SelectabelChannel的子类。

(3)多路复用器Selector
===>它是javaNio编程的基础,熟练掌握Selector对于掌握NIO编程至关重要。
===>多路复用器提供选择已经就绪的任务的能力。
===>简单的来讲,Selector会不断轮询注册在其上的Channel。如果某个Channel上面有新的TCP连接接入,读和写事件。这个Channel就处于就绪状态,会被Selector轮询出来,然后通过SelectionKey可以获取就绪Channel的集合,进行后续的I/O操作。
===>一个多路复用器Selector可以同时轮询多个Channel,由于JDK使用epoll()代替传统的select实现。所以它并没有最大连接句柄1024/2048的限制。这也意味者只需要一个线程负责Selector的轮询,就可以接入成千上万的客户端。

【六】NIO实现服务端通信序列图

NIO简单实现服务端代码

package com.sxf.test.netty;

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;
import java.util.Set; import org.apache.commons.lang3.StringUtils; public class NioServer implements Runnable{ //打开serverSocketChannel,用于监听客户端链接,它是所有客户端链接的父管道
private ServerSocketChannel serverSocketChannel; //创建多路复用器
private Selector selector; private volatile boolean stop=false; //初始化服务器
public NioServer(Integer port){
try {
//创建多路复用器
selector=Selector.open();
//打开serverSocketChannel,用于监听客户端链接,它是所有客户端链接的父管道
serverSocketChannel=ServerSocketChannel.open();
//非阻塞模式
serverSocketChannel.configureBlocking(false);
//绑定监听端口
serverSocketChannel.socket().bind(new InetSocketAddress(port),1024);
//将serverSocketChannel注册到复用器上,并轮询出读的就绪事件。
serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
System.out.println("NioServer.NioServer()=====>NIOServer start...");
} catch (Exception e) {
System.out.println("NioServer.NioServer()"+e);
}
} public void stop(){
this.stop=true;
} /**
* 服务器执行过程
*/
@Override
public void run() {
while(!stop){
try {
//
selector.select();
//多路复用器,选出已经就绪的事件
Set<SelectionKey> selectedKeys=selector.selectedKeys();
//遍历就绪事件进行处理
Iterator<SelectionKey> it=selectedKeys.iterator();
while(it.hasNext()){
//其中一个事件
SelectionKey selectionKey=it.next();
it.remove();
handleInput(selectionKey);
} } catch (Exception e) {
// TODO: handle exception
System.out.println("NioServer.run()"+e);
}
}
//多路复用器关闭后,所有注册在上面的Channel和Pipe都会被自动去注册并关闭,所以不需要重复释放资源
if(selector!=null){
try {
selector.close();
} catch (Exception e) { }
}
} private void handleInput(SelectionKey selectionKey) throws IOException{
//判断是否有效
if(selectionKey.isValid()){ //=============处理新接入的网络链接================
if(selectionKey.isAcceptable()){
//从事件key上获取请求通道
ServerSocketChannel requestChannel=(ServerSocketChannel) selectionKey.channel();
SocketChannel channel=requestChannel.accept();
//设置非阻塞模式
channel.configureBlocking(false);
channel.register(selector,selectionKey.OP_READ);
} //=============处理可以读取请求内容的链接================
if(selectionKey.isReadable()){
//从事件中得到链接通道
SocketChannel channel=(SocketChannel) selectionKey.channel();
//声明缓冲区,准备读取数据。
ByteBuffer readByteBuffer=ByteBuffer.allocate(1024);
//读取请求管道的数据
int readBytes=channel.read(readByteBuffer); if(readBytes>0){
//读取到内容
readByteBuffer.flip();
byte[] requestByte=new byte[readByteBuffer.remaining()];
readByteBuffer.get(requestByte);
String requestBody=new String(requestByte, "utf-8");
System.out.println("NioServer.handleInput()the nio server receive body(接收到请求内容为)===>"+requestBody);
//模拟处理请求内容
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String response="中华兴旺";
//将处理结果进行响应
doWrite(channel, response);
}else if(readBytes<0){
//客户端关闭
selectionKey.cancel();
channel.close();
}else{
//读到0字节忽略
}
}
}
} /**
* 响应请求
* @param socketChannel
* @param response
* @throws IOException
*/
public void doWrite(SocketChannel socketChannel,String response) throws IOException{
if(StringUtils.isNotBlank(response)){
byte[] res=response.getBytes();
ByteBuffer writeByteBuffer=ByteBuffer.allocate(res.length);
writeByteBuffer.put(res);
writeByteBuffer.flip();
socketChannel.write(writeByteBuffer);
}
} public static void main(String[] args) throws IOException, InterruptedException {
NioServer nioServer=new NioServer(8000);
new Thread(nioServer,"NioServer===>").start();
Thread.sleep(1000*10);
NioClient nioClient=new NioClient("127.0.0.1", 8000);
new Thread(nioClient,"NioClient===>").start(); while(true){
Thread.sleep(1000*60);
}
}
}

【七】Nio客户端链接

NIO简单实现客户端代码

package com.sxf.test.netty;

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.SocketChannel;
import java.util.Iterator;
import java.util.Set; public class NioClient implements Runnable {
/**
* 请求的地址
*/
private String host;
/**
* 请求的端口号
*/
private int port;
/**
* 请求的多路复用器
*/
private Selector selector;
/**
* 请求的通道
*/
private SocketChannel socketChannel;
/**
* 客户端是否停止
*/
private volatile boolean stop=false; public NioClient(String host,Integer port) throws IOException {
try {
this.host=host;
this.port=port;
this.selector=Selector.open();
this.socketChannel=SocketChannel.open();
socketChannel.configureBlocking(false);
} catch (Exception e) {
}
} @Override
public void run() {
//链接服务端
try {
doConnect();
} catch (Exception e) {
System.out.println("NioClient.run()"+e);
} //循环发送请求
while(!stop){
try {
//超时时间
selector.select();
//获取就绪事件的key
Set<SelectionKey> selectionKeys=selector.selectedKeys();
//开始遍历事件
Iterator<SelectionKey> it=selectionKeys.iterator();
while(it.hasNext()){
SelectionKey selectionKey=it.next();
it.remove();
try {
handlerInput(selectionKey);
} catch (Exception e) {
//关闭
selectionKey.cancel();
if(selectionKey.channel()!=null){
selectionKey.channel().close();
}
}
}
} catch (Exception e) {
System.out.println("NioClient.run()"+e);
}
} //多路复用器关闭后,所有注册在上面的channel和Pipe等资源都会被自动去注册并关闭
//所以不需要重复释放资源
// if(selector!=null){
// try {
// selector.close();
// } catch (Exception e) {
// e.printStackTrace();
// }
// } } //链接操作
private void doConnect() throws IOException{
//判断是否能链接到服务器
if(socketChannel.connect(new InetSocketAddress(host,port))){
socketChannel.register(selector, SelectionKey.OP_READ);
}else{
socketChannel.register(selector,SelectionKey.OP_CONNECT);
}
} //发送请求操作
private void write(SocketChannel socketChannel) throws IOException{
byte[] requestByte="shangxiaofei".getBytes();
//将请求内容写入缓冲区
ByteBuffer requestByteBuffer=ByteBuffer.allocate(requestByte.length);
requestByteBuffer.put(requestByte);
requestByteBuffer.flip();
//向请求通道写数据
socketChannel.write(requestByteBuffer);
if(!requestByteBuffer.hasRemaining()){
System.out.println("NioClient.write()向服务端发送请求");
}
} private void handlerInput(SelectionKey selectionKey) throws IOException{
//判断是否有效
if(selectionKey.isValid()){
SocketChannel channel=(SocketChannel) selectionKey.channel();
//已成功和服务端建立链接
if(selectionKey.isConnectable()){
if(channel.finishConnect()){
//成功和服务端建立链接,开始写数据
channel.register(selector, selectionKey.OP_READ);
write(channel);
}else{
//链接失败,退出
System.exit(1);
}
}
if(selectionKey.isReadable()){
//读取事件就绪
ByteBuffer readByteBuffer=ByteBuffer.allocate(1024);
int a=channel.read(readByteBuffer);
if(a>0){
//读取到数据
readByteBuffer.flip();
byte[] response=new byte[readByteBuffer.remaining()];
readByteBuffer.get(response);
String responseBody=new String(response,"utf-8");
System.out.println("NioClient.handlerInput(响应内容)===>"+responseBody);
//退出
this.stop=true;
}else if(a<0){
//服务端链路关闭
selectionKey.cancel();
channel.close();
}else{
//读到0字节忽略
}
} } } }

【Netty】netty学习之nio了解的更多相关文章

  1. netty深入学习之一: 入门篇

    netty深入学习之一: 入门篇 本文代码下载: http://download.csdn.net/detail/cheungmine/8497549 1)Netty是什么 Netty是Java NI ...

  2. 关于Netty的学习前总结

    摘要 前段时间一直在学习netty因为工作忙的原因没有写一个学习的总结,今天抽个空先把总结写了吧.事先声明,本文不会详细的介绍每一个部分不过每个部分都会附上讲解详细的url.本文只是为了解释通Nett ...

  3. netty深入学习之中的一个: 入门篇

    netty深入学习之中的一个: 入门篇 本文代码下载: http://download.csdn.net/detail/cheungmine/8497549 1)Netty是什么 Netty是Java ...

  4. Netty源代码学习——EventLoopGroup原理:NioEventLoopGroup分析

    类结构图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd29ya2luZ19icmFpbg==/font/5a6L5L2T/fontsize/400/f ...

  5. 7. 彤哥说netty系列之Java NIO核心组件之Selector

    --日拱一卒,不期而至! 你好,我是彤哥,本篇是netty系列的第七篇. 简介 上一章我们一起学习了Java NIO的核心组件Buffer,它通常跟Channel一起使用,但是它们在网络IO中又该如何 ...

  6. 《精通并发与Netty》学习笔记(01 - netty介绍及环境搭建)

    一.Netty介绍     Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序.     ...

  7. Netty 框架学习 —— EventLoop 和线程模型

    EventLoop 接口 Netty 是基于 Java NIO 的,因此 Channel 也有其生命周期,处理一个连接在其生命周期内发生的事件是所有网络框架的基本功能.通常来说,我们使用一个线程来处理 ...

  8. [Netty] - Netty IN ACTION(导言)

    最近没什么事儿做,刚好看到有需要网络编程的知识,java中有NIO和IO两种不同的方式,但是NIO的编写比较麻烦,刚好找到一个成熟的网络框架Netty.接下来的一个月就准备将Netty IN ACTI ...

  9. [Netty] - Netty入门(最简单的Netty客户端/服务器程序)

    Java中的NIO是一种解决阻塞式IO问题的基本技术,但是NIO的编写对java程序员是有比较高的要求的.那么Netty就是一种简化操作的一个成熟的网络IO编程框架.这里简单介绍一个程序,代码是< ...

  10. NetCore Netty 框架 BT.Netty.RPC 系列随讲 二 WHO AM I 之 NETTY/NETTY 与 网络通讯 IO 模型之关系?

    一:NETTY 是什么? Netty 是什么?  这个问题其实百度上一搜一堆. 这是官方话的描述:Netty 是一个基于NIO的客户.服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个 ...

随机推荐

  1. MySQL5.7 半同步复制

    一.概述 5.5与5.7的半同步复制可能存在差异,从MySQL5.5开始,MySQL以插件的形式支持半同步复制 异步:默认情况下,MySQL复制是异步的.主库在执行完客户端提交的事务后会立即将结果返给 ...

  2. 1-26-1-expect无交互式-正则表达式

    大纲: 1.expect环境搭建及脚本编写 概述 expect脚本详解 expect环境搭建 expect脚本实现ssh远程连接 expect脚本实现ssh远程连接(通过shell传递参数) 2.正则 ...

  3. HDU 4681 STRING dp+暴力。

    题意:不说了很好懂. 这题这么水= =...当时竟然没有勇气暴力搜一下.昨天(好吧前天.)比赛的时候胃疼,看到这题想了一个办法就是对每一个出现最短的C串前后连接然后对这个串求最长公共子序列.其实优化一 ...

  4. C++:栈(stack)的模板类实现

    1.基本概念 栈中的元素遵守“先进后出”的原则(LIFO,Last In First Out) 只能在栈顶进行插入和删除操作 压栈(或推入.进栈)即push,将数据放入栈顶并将栈顶指针加一 出栈(或弹 ...

  5. watch和computed的用法区别是什么?

    在模板中绑定表达式是非常便利的,但是它们实际上只用于简单的操作.模板是为了描述视图的结构.在模板中放入太多的逻辑会让模板过重且难以维护.这就是为什么 Vue.js 将绑定表达式限制为一个表达式.如果需 ...

  6. sql杂记

    Create procedure 存储过程的声明 PIVOT的一般语法是:PIVOT(聚合函数(列) FOR 列 in (…) )AS P 通俗简单的说:PIVOT就是行转列,UNPIVOT就是列传行 ...

  7. resizable可调整尺寸组件

    Resizable 可调整尺寸不依赖于其他组件 1.用法:通过标记创建可调整尺寸(resizable)对象 <div class="easyui-resizable" sty ...

  8. Python面向对象的三大特征 --- 封装、继承、多态

    一.封装 1)封装:是面向对象的一大特点:将属性和方法封装在一个抽象类中.外界使用类创建对象,然后让对象调用内部方法.对象方法的细节都被封装在类的内部. class Person():   def _ ...

  9. Mac怎么安装Windows10

    当前  Windows10 系统的预览版已经出来,对于新系统感兴趣的不只是使用 PC 电脑的用户,还有一些是当前正在使用 Mac 系统的用户.其实安装 Windows 10 与以前安装 Windows ...

  10. 一个浮动 css3效果

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...