有人叫new IO 我这里就叫Non-block IO

经典概念:

Buffer(缓冲区):之前直接通过流,现在提供一个buffer存放数据。

Channel:管道,包括ServerSocketChannel和SocketChannel

Selecor(选择器、多路复用器):SocketChannel注册到选择器上,轮询selector上的所有socketChannel ,根据通道的状态来执行相关操作。通道有链接状态、阻塞状态、可读状态、可写状态(Connect、Accept、Read、Write)。

Buffer:

和原来的IO的一个重要区别,面向流到面向缓冲区的转变。ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer

pos位置、limit长度、cap容量

朝pos装一个元素,pos增加1,get(Index)时pos时不发生变化的。所以在每批put后要flit()一下。put(value)和get()都会让pos发生递增。

IntBuffer.wrap(arr)可以将Int数组转换成IntBuffer,wrap方法影响limit;

put(arr)不影响limit;

buffer1.position(1);

buffer1.duplicate()复制;

Buffer1.remaining()可读长度;

Channel:

通道是双向的,SocketChannel、ServerSocketChannel,Selector不断轮询通道的状态,一旦有通道数据准备好了,selector就把这个通道拿出来(通过key可以拿出来)。

selector:

特别强调selector,理论上讲selector可以负责超大数据量的Channel,没有限制多少个客户端,因为只有一个线程在轮询Channel,也用epoll代替传统的select。

但是还是同步的,因为读写操作还是通过java代码实现的。

客户端:

 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 Server implements Runnable{
//1 多路复用器(管理所有的通道)
private Selector seletor;
//2 建立缓冲区
private ByteBuffer readBuf = ByteBuffer.allocate(1024);
//3
private ByteBuffer writeBuf = ByteBuffer.allocate(1024);
public Server(int port){
try {
//1 打开路复用器
this.seletor = Selector.open();
//2 打开服务器通道
ServerSocketChannel ssc = ServerSocketChannel.open();
//3 设置服务器通道为非阻塞模式
ssc.configureBlocking(false);
//4 绑定地址
ssc.bind(new InetSocketAddress(port));
//5 把服务器通道注册到多路复用器上,并且监听阻塞事件
ssc.register(this.seletor, SelectionKey.OP_ACCEPT); System.out.println("Server start, port :" + port); } catch (IOException e) {
e.printStackTrace();
}
} @Override
public void run() {
while(true){
try {
//1 必须要让多路复用器开始监听
this.seletor.select();
//2 返回多路复用器已经选择的结果集
Iterator<SelectionKey> keys = this.seletor.selectedKeys().iterator();
//3 进行遍历
while(keys.hasNext()){
//4 获取一个选择的元素
SelectionKey key = keys.next();
//5 直接从容器中移除就可以了
keys.remove();
//6 如果是有效的
if(key.isValid()){
//7 如果为阻塞状态
if(key.isAcceptable()){
this.accept(key);
}
//8 如果为可读状态
if(key.isReadable()){
this.read(key);
}
//9 写数据
if(key.isWritable()){
//this.write(key); //ssc
}
} }
} catch (IOException e) {
e.printStackTrace();
}
}
} private void write(SelectionKey key){
//ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
//ssc.register(this.seletor, SelectionKey.OP_WRITE);
} private void read(SelectionKey key) {
try {
//1 清空缓冲区旧的数据
this.readBuf.clear();
//2 获取之前注册的socket通道对象
SocketChannel sc = (SocketChannel) key.channel();
//3 读取数据
int count = sc.read(this.readBuf);
//4 如果没有数据
if(count == -1){
key.channel().close();
key.cancel();
return;
}
//5 有数据则进行读取 读取之前需要进行复位方法(把position 和limit进行复位)
this.readBuf.flip();
//6 根据缓冲区的数据长度创建相应大小的byte数组,接收缓冲区的数据
byte[] bytes = new byte[this.readBuf.remaining()];
//7 接收缓冲区数据
this.readBuf.get(bytes);
//8 打印结果
String body = new String(bytes).trim();
System.out.println("Server : " + body); // 9..可以写回给客户端数据 } catch (IOException e) {
e.printStackTrace();
} } private void accept(SelectionKey key) {
try {
//1 获取服务通道
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
//2 执行阻塞方法
SocketChannel sc = ssc.accept();
//3 设置阻塞模式
sc.configureBlocking(false);
//4 注册到多路复用器上,并设置读取标识
sc.register(this.seletor, SelectionKey.OP_READ);
} catch (IOException e) {
e.printStackTrace();
}
} public static void main(String[] args) { new Thread(new Server(8765)).start();;
} }

客户端:

 import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; public class Client { //需要一个Selector
public static void main(String[] args) { //创建连接的地址
InetSocketAddress address = new InetSocketAddress("127.0.0.1", 8765); //声明连接通道
SocketChannel sc = null; //建立缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024); try {
//打开通道
sc = SocketChannel.open();
//进行连接
sc.connect(address); while(true){
//定义一个字节数组,然后使用系统录入功能:
byte[] bytes = new byte[1024];
System.in.read(bytes); //把数据放到缓冲区中
buf.put(bytes);
//对缓冲区进行复位
buf.flip();
//写出数据
sc.write(buf);
//清空缓冲区数据
buf.clear();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(sc != null){
try {
sc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} } }

架构师养成记--18.NIO的更多相关文章

  1. 架构师养成记--15.Disruptor并发框架

    一.概述 disruptor对于处理并发任务很擅长,曾有人测过,一个线程里1s内可以处理六百万个订单,性能相当感人. 这个框架的结构大概是:数据生产端 --> 缓存 --> 消费端 缓存中 ...

  2. 架构师养成记--35.redis集群搭建

    前记:redis哨兵经验之谈.哨兵做主从切换可能要花费一两秒,这一两秒可能会丢失很多数据.解决方法之一是在java代码中做控制,try catch 到 链接断开的异常就sleep 一两秒钟再conti ...

  3. 架构师养成记--22.客户端与服务器端保持连接的解决方案,netty的ReadTimeoutHandler

    概述 保持客户端与服务器端连接的方案常用的有3种 1.长连接,也就是客户端与服务器端一直保持连接,适用于客户端比较少的情况. 2.定时段连接,比如在某一天的凌晨建立连接,适用于对实时性要求不高的情况. ...

  4. 架构师养成记--21.netty编码解码

    背景 作为网络传输框架,免不了哟啊传输对象,对象在传输之前就要序列化,这个序列化的过程就是编码过程.接收到编码后的数据就需要解码,还原传输的数据. 代码 工厂类 import io.netty.han ...

  5. 架构师养成记--20.netty的tcp拆包粘包问题

    问题描述 比如要发ABC DEFG HIJK 这一串数据,其中ABC是一个包,DEFG是一个包,HIJK是一个包.由于TCP是基于流发送的,所以有可能出现ABCD EFGH 这种情况,那么ABC和D就 ...

  6. 架构师养成记--19.netty

    一.Netty初步 为什么选择Netty? 和NIO比较,要实现一个通信要简单得很多,性能很好.分布式消息中间件.storm.Dubble都是使用Netty作为底层通信. Netty5.0要求jdk1 ...

  7. 架构师养成记--17.disrunptor 多生产者多消费者

    入口: import java.nio.ByteBuffer; import java.util.UUID; import java.util.concurrent.CountDownLatch; i ...

  8. 架构师养成记--14.重入锁ReentrantLock 和 读写锁 ReentrantReadWriteLock

    ReentrantLock 有嗅探锁定和多路分支等功能,其实就是synchronized,wait,notify的升级. this锁定当前对象不方便,于是就有了用new Object()来作为锁的解决 ...

  9. 架构师养成记--12.Concurrent工具类CyclicBarrier和CountDownLatch

    java.util.concurrent.CyclicBarrier 一组线程共同等待,直到达到一个公共屏障点. 举个栗子,百米赛跑中,所有运动员都要等其他运动员都准备好后才能一起跑(假如没有发令员) ...

随机推荐

  1. CloudStack 4.1快照测试

    目前4.1只支持存储快照,4.2能支持内快照 1. 选中实例 2. 查看实例卷 3. 创建快照 4. 通过快照创建模板 5. 查看通过快照创建的模板 6. 通过快照创建模板生成的实例 7. 自动定制创 ...

  2. socket的protocal参数

    Documentation for socket() on Linux is split between various manpages including ip(7) that specifies ...

  3. jQuery绑定事件的四種方式

    这篇文章主要介绍的是jQuery绑定事件的四种方式相关内容,下面我们就与大家一起分享. jQuery绑定事件的四种方式 jQuery提供了多种绑定事件的方式,每种方式各有其特点,明白了它们之间的异同点 ...

  4. linux查看端口号监听状态

    lsof -i:<port> netstat -tunlp | grep <port>

  5. thinkphp 调用wsdl接口实例化SoapClient抛出异常

    异常:Message:SOAP-ERROR: Parsing WSDL: Couldn't load from 'http://*****?wsdl' : failed to load externa ...

  6. Hello_Area_Description 任务三:Project Tango采集区域描述数据

    Permission Dialogs for Users in Java在Java中用户使用的权限对话框 Tango works by using visual cues from the devic ...

  7. 命令行传递参数并排序 AS实现加法

    题目:从命令行输入参数并进行排序 1.实验准备 Integer提供了能在 int 类型和 String 类型之间互相转换的方法,还提供了处理 int 类型时非常有用的其他一些常量和方法. static ...

  8. [转]使用WCF 4.0 构建 REST Service

    本文转自:http://www.cnblogs.com/lanvige/archive/2010/12/03/set_up_rest_service_with_wcf_4.html 用过一段时间的Ru ...

  9. [Delphi]编译条件

    当软件在多个DELPHI版本下编译时,需要处理各版本的不同情况,使用编译条件技术实现. 万一博客,编译指令基础使用介绍:http://www.cnblogs.com/del/category/1686 ...

  10. WPF自定义控件之列表滑动特效 PowerListBox

    列表控件是应用程序中常见的控件之一,对其做一些绚丽的视觉特效,可以让软件增色不少. 本人网上看过一个视频,是windows phone 7系统上的一个App的列表滚动效果,效果非常炫 现在在WPF上用 ...