【正文】netty源码死磕1.3: 

Java NIO Channel

1. 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));

源码:

代码工程:  JavaNioDemo.zip

下载地址:在疯狂创客圈QQ群文件共享。



无编程不创客,无案例不学习。疯狂创客圈,一大波高手正在交流、学习中!

疯狂创客圈 Netty 死磕系列 10多篇深度文章: 【博客园 总入口】  QQ群:104131248

Channel (Java NIO)的更多相关文章

  1. Java NIO 完全学习笔记(转)

    本篇博客依照 Java NIO Tutorial翻译,算是学习 Java NIO 的一个读书笔记.建议大家可以去阅读原文,相信你肯定会受益良多. 1. Java NIO Tutorial Java N ...

  2. Java NIO Tutorial

    Java NIO Tutorial     Jakob JenkovLast update: 2014-06-25

  3. Java NIO系列教程(十一) Java NIO 与 IO

    Java NIO系列教程(十一) Java NIO与IO 当学习了 Java NIO 和 IO 的 API 后,一个问题马上涌入脑海: 我应该何时使用 IO,何时使用 NIO 呢?在本文中,我会尽量清 ...

  4. java NIO系列教程1

    ava NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式. Java NIO: Channel ...

  5. 【Java nio】java nio笔记

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

  6. JAVA NIO简介-- Buffer、Channel、Charset 、直接缓冲区、分散和聚集、文件锁

    IO  是主存和外部设备 ( 硬盘.终端和网络等 ) 拷贝数据的过程. IO 是操作系统的底层功能实现,底层通过 I/O 指令进行完成. Java标准io回顾 在Java1.4之前的I/O系统中,提供 ...

  7. [翻译] java NIO Channel

    原文地址:http://tutorials.jenkov.com/java-nio/channels.html JAVA NIO channels和流的概念很像,下面是他们的一些区别: 你可以对cha ...

  8. 转:Java NIO系列教程(七) Socket Channel

    Java NIO中的SocketChannel是一个连接到TCP网络套接字的通道.可以通过以下2种方式创建SocketChannel: 打开一个SocketChannel并连接到互联网上的某台服务器. ...

  9. 转:Java NIO系列教程(六) File Channel

    Java NIO中的FileChannel是一个连接到文件的通道.可以通过文件通道读写文件. FileChannel无法设置为非阻塞模式,它总是运行在阻塞模式下. 打开FileChannel 在使用F ...

随机推荐

  1. 【前端开发】 5分钟创建 Mock Server

    http://blog.csdn.net/wxqee/article/details/50165581 NOTIFY 官网文档现在已经很简约.很强大了,建议直接点击这里: Getting Starte ...

  2. Node.js 使用jQuery取得Nodejs http服务端返回的JSON对象示例

    server.js代码: // 内置http模块,提供了http服务器和客户端功能(path模块也是内置模块,而mime是附加模块) var http=require("http" ...

  3. ubuntu用su切换,输入密码提示认证失败解决办法

    ubuntu用su切换,输入密码提示认证失败,经查阅原来Ubuntu安装后,root用户默认是被锁定了的,不允许登录,也不允许 su 到 root ,对于桌面用户来说这个可能是为了增强安全性. 终端下 ...

  4. Android学习(四) Layout五大布局

    我们知道Android系统应用程序一般是由多个Activity组成,而这些Activity以视图的形式展现在我们面前, 视图都是由一个一个的组件构成的.组件就是我们常见的Button.TextEdit ...

  5. 网络设备 | Cisco设备镜像文件损坏无法启动处理(tftp + rommon模式)

    从正常的设备上通过tftp下载.bin镜像(G0/0口与pc设置同一网段互通) 进入坏的路由器rommon模式 在没有IOS情况下,默认进入了ROMMON模式:在ROMMON模式下输入以下命令设置f0 ...

  6. mysql中去重复记录

    Distinct 这个只能放在查询语句的最前面 参考 : https://www.cnblogs.com/lushilin/p/6187743.html

  7. Write operations are not allowed in read-only mode (FlushMode.MANUAL)

    © 版权声明:本文为博主原创文章,转载请注明出处 1.问题描述 搭建SSH框架后,为测试事务配置是否生效,因此在事务配置中取消了保存方法,然后再保存方法中手动抛出异常(已测试配置事务后没有保存成功), ...

  8. linux下常用网页查看下载工具--wget

    http://www.linuxidc.com/Linux/2015-06/118256.htm 5 个基于Linux命令行的文件下载和网站浏览工具 rTorrent.wget.cURL.w3m.El ...

  9. php跨域共享session

    . $gb_DBHOSTname = "127.0.0.1"; //主机的名称或是IP地址 02 $gb_DBname = "dbname"; //数据库名称 ...

  10. 通过Lock对象以及Condition对象实现多线程同步

    通过Lock对象以及Condition对象实现多线程同步: 在之前的学习中,无论是通过synchronized建立同步代码块,还是通过synchronized建立同步函数,都是把对象看成一把锁来实现同 ...