出处: Java NIO Channel

1.1. Java NIO Channel的特点

 和老的OIO相比,通道和NIO流(非阻塞IO)主要有以下几点区别:

  (1)OIO流一般来说是单向的(只能读或者写),通道可以读也可以写。

  (2)OIO流值读写阻塞的,而通道可以异步读写。

  (3)通道总是基于缓冲区Buffer来读写。

1.2. Channel类型

 下面列出Java NIO中最重要的集中Channel的实现:

  (1)FileChannel

  (2)DatagramChannel

  (3)SocketChannel

  (4)ServerSocketChannel

 四种通道的说明如下:

    FileChannel 用于文件的数据读写。

    DatagramChannel 用于UDP的数据读写。

    SocketChannel 用于TCP的数据读写。

    ServerSocketChannel 允许我们监听TCP链接请求,每个请求会创建会一个SocketChannel。

 这个四种通道,涵盖了 UDP 和 TCP网络 IO以及文件 IO的操作。下面从通道的新建、读取、写入、关闭等四个操作,四种通道进行简单的介绍。

1.3. FileChannel

  FileChannel 是操作文件的Channel,我们可以通过 FileChannel 从一个文件中读取数据,也可以将数据写入到文件中。

  注意,FileChannel 不能设置为非阻塞模式。

 操作一:打开 FileChannel通道

RandomAccessFile aFile = new RandomAccessFile("test.txt","rw");
FileChannel inChannel = aFile.getChannel();

 操作二:读取数据

ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);

 操作三:写入数据

String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
while(buf.hasRemaining())
{
channel.write(buf);
}

 操作四:关闭

  channel.close();

  当我们对 FileChannel 的操作完成后,必须将其关闭。

 操作五:强制刷新磁盘

  channel.force(true);

  FileChannel的force()方法将所有未写入的数据从通道刷新到磁盘中。在你调用该force()方法之前,出于性能原因,操作系统可能会将数据缓存在内存中,因此您不能保证写入通道的数据实际上写入磁盘。

1.4. SocketChannel

  有两种Socket通道,一个是客户端的SocketChannel,一个是负责服务器端的Socket通道ServerSocketChannel。SocketChannel与OIO中的Socket类对应,ServerSocketChannel对应于OIO中的ServerSocket类相NIO。

  两种Socket通道新增的通道都支持阻塞和非阻塞两种模式。在阻塞模式下的通道的创建、关闭、读写操作如下:

 操作一:创建

  SocketChannel socketChannel = SocketChannel.open();

  socketChannel.connect(new InetSocketAddress("127.0.0.1",80));

  这个是客户端的创建。当一个服务器端的ServerSocketChannel 接受到连接请求时,也会返回一个 SocketChannel 对象。

 操作二:读取

  ByteBuffer buf = ByteBuffer.allocate(48);

  int bytesRead = socketChannel.read(buf);

  如果 read()返回 -1,那么表示连接中断了.

 操作三:写入数据

String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
while(buf.hasRemaining()) {
channel.write(buf);
}

 操作四:关闭

  socketChannel.close();

  在非阻塞模式,我们可以设置 SocketChannel 为异步模式,这样我们的 connect,read,write 都是异步的了.

 操作一:连接

socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("127.0.0.1",80));
while(! socketChannel.finishConnect() ){
//wait,or do something else...
}

  在异步模式中,或许连接还没有建立,socketChannel.connect 方法就返回了,因此我们不断的自旋,检查当前是否是连接到了主机。

 操作二:非阻塞读写

  在异步模式下,读写的方式是一样的.

  在读取时,因为是异步的,因此我们必须检查 read 的返回值,来判断当前是否读取到了数据.

ServerSocketChannel

  ServerSocketChannel 顾名思义,是用在服务器为端的,可以监听客户端的 TCP 连接,例如:

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(9999));
while(true){
SocketChannel socketChannel = serverSocketChannel.accept();
//do something with socketChannel...
}

操作四:关闭

  ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

  serverSocketChannel.close();

 1.4.1. 监听连接

  我们可以使用ServerSocketChannel.accept()方法来监听客户端的 TCP 连接请求,accept()方法会阻塞,直到有连接到来,当有连接时,这个方法会返回一个 SocketChannel 对象:

while(true){
SocketChannel socketChannel = serverSocketChannel.accept();
//do something with socketChannel...
}
 1.4.2. 非阻塞模式

  在非阻塞模式下,accept()是非阻塞的,因此如果此时没有连接到来,那么 accept()方法会返回null:

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(9999));
serverSocketChannel.configureBlocking(false);
while(true){
SocketChannel socketChannel = serverSocketChannel.accept();
if(socketChannel != null){
//do something with socketChannel...
}
}

1.5. DatagramChannel

  DatagramChannel 是用来处理 UDP 连接的.

 操作一:打开

  DatagramChannel channel = DatagramChannel.open();

  channel.socket().bind(new InetSocketAddress(9999));

 操作二:读取数据

ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
channel.receive(buf);

 操作三:发送数据

String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
int bytesSent = channel.send(buf,new InetSocketAddress("example.com",80));

 连接到指定地址

  因为 UDP 是非连接的,因此这个的 connect 并不是向 TCP 一样真正意义上的连接,因此我们仅仅可以从指定的地址中读取或写入数据.

  channel.connect(new InetSocketAddress("example.com",80));

(三:NIO系列) Java NIO Channel的更多相关文章

  1. 【Java nio】java nio笔记

    缓冲区操作:缓冲区,以及缓冲区如何工作,是所有I/O的基础.所谓“输入/输出”讲的无非就是把数据移出货移进缓冲区.进程执行I/O操作,归纳起来也就是向操作系统发出请求,让它要么把缓冲区里的数据排干,要 ...

  2. Java-杂项-java.nio:java.nio

    ylbtech-Java-杂项-java.nio:java.nio java.nio全称java non-blocking IO,是指jdk1.4 及以上版本里提供的新api(New IO) ,为所有 ...

  3. java的nio之:java的nio系列教程之channel的概念

    一:java的nio的channel Java NIO的通道类似流,但又有些不同: ==>既可以从通道中读取数据,又可以写数据到通道.但流的读写通常是单向的. ==>通道可以异步地读写. ...

  4. 转:Java NIO系列教程(二) Channel

    Java NIO的通道类似流,但又有些不同: 既可以从通道中读取数据,又可以写数据到通道.但流的读写通常是单向的. 通道可以异步地读写. 通道中的数据总是要先读到一个Buffer,或者总是要从一个Bu ...

  5. java的nio之:java的nio系列教程之channel的数据交换

    在Java NIO中,如果两个通道中有一个是FileChannel,那你可以直接将数据从一个channel(译者注:channel中文常译作通道)传输到另外一个channel. transferFro ...

  6. 【NIO】Java NIO之选择器

    一.前言 前面已经学习了缓冲和通道,接着学习选择器. 二.选择器 2.1 选择器基础 选择器管理一个被注册的通道集合的信息和它们的就绪状态,通道和选择器一起被注册,并且选择器可更新通道的就绪状态,也可 ...

  7. 【NIO】Java NIO之通道

    一.前言 前面学习了缓冲区的相关知识点,接下来学习通道. 二.通道 2.1 层次结构图 对于通道的类层次结构如下图所示. 其中,Channel是所有类的父类,其定义了通道的基本操作.从 Channel ...

  8. 我的Java开发学习之旅------>Java NIO 报java.nio.charset.MalformedInputException: Input length = 1异常

    今天在使用Java NIO的Channel和Buffer进行文件操作时候,报了java.nio.charset.MalformedInputException: Input length = 1异常, ...

  9. 【JAVA NIO】java NIO

    本文是博主深入学习Netty前的一些铺垫,之前只是使用Netty,用的很粗暴,导包,上网找个DEMO就直接用,对Netty中的组件了解并不深入. 于是再此总结下基础,并对一些核心组件作如下记录: 1. ...

  10. 【NIO】Java NIO之缓冲

    一.前言 在笔者打算学习Netty框架时,发现很有必要先学习NIO,因此便有了本博文,首先介绍的是NIO中的缓冲. 二.缓冲 2.1 层次结构图 除了布尔类型外,其他基本类型都有相对应的缓冲区类,其继 ...

随机推荐

  1. NOIP2017 D2T2 宝藏

    洛谷P3959 其实就是一道暴力搜索题……只是需要一个状态压缩的剪枝比较难想而已 这根本不叫dfs!只是一个递归而已……开始就被dfs坑了 思路: 首先一个基本的预处理 数据范围n≤12,m≤5000 ...

  2. python入门 python字符串换行显示、字符串太长\连接多行

    #coding:utf-8#/usr/bin/python"""2018-11-03dinghanhua缩进换行""" "&quo ...

  3. postman—UI测试

    思路 发送请求去拿到网站的响应->html 解析HTML标签,判断一些元素是否显示 目的 快速检查UI是否正确 测试地址 http://www.itest.info/courses 我们接下来要 ...

  4. 倍增O(1)求区间&值与|值

    ;i<=n;++i) f[i][]=a[i],g[i][]=a[i]; ;(<<j)<=n;++j) ;(i+(<<j)-)<=n;i++) { f[i][j ...

  5. 「树形结构 / 树形DP」总结

    Codeforces 686 D. Kay and Snowflake 要求$O(n)$求出以每个节点为根的重心. 考虑对于一个根节点$u$,其重心一定在[各个子树的重心到$u$]这条链上.这样就能够 ...

  6. python 存取字典dict

    数据处理的时候主要通过两个函数(1):np.save(“test.npy”,数据结构) ----存数据(2):data =np.load('test.npy") ----取数据 1.存列表 ...

  7. Build安装版的UE4

    在项目中自己编译的引擎分发给团队可以参考以下两个链接 http://jackknobel.com/BuildGraph/Building-an-installed-ue4/ https://docs. ...

  8. 2018 CCPC 秦皇岛 I (状压DP)

    题意: 首先t组数据  (t<=5),一个n代表有n件东西,每个东西可以代表两个物品,商品或者袋子,每个都有个值,如果这个要代表袋子的话,当前就代表是容量,而且必须把其他几件不是袋子的物品放一些 ...

  9. Oracle Like子句

    Oracle Like子句 作者:初生不惑 Oracle基础 评论:0 条 Oracle技术QQ群:175248146 在本教程中,您将学习如何使用Oracle LIKE运算符来测试列中的值是否与指定 ...

  10. Elasticsearch结构化搜索与查询

    Elasticsearch 的功能之一就是搜索,搜索主要分为两种类型,结构化搜索和全文搜索.结构化搜索是指有关查询那些具有内在结构数据的过程.比如日期.时间和数字都是结构化的:它们有精确的格式,我们可 ...