一、通道(Channel):由 java.nio.channels 包定义的。Channel 表示 IO 源与目标打开的连接。Channel 类似于传统的“流”。只不过 Channel本身不能直接访问数据,Channel 只能与Buffer 进行交互。
二、Channel重要实现
- FileChannel:操作文件的读写
- SocketChannel:通过TCP读写网络数据
- ServerSocketChannel:监听TCP连接,你能利用它创建一个最简单的Web服务器
- DatagramChannel:通过UDP读写网络数据
三、FileChannel 的文件读写
1)利用FileChannel 本身提供的transferTo进行数据的读写。
package com.troy.nio.application; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.channels.FileChannel; public class Channel { public static void main(String[] args) throws Exception { //读取文件 FileInputStream fileInputStream = new FileInputStream("d:/t.txt"); //写出文件 FileOutputStream fileOutputStream = new FileOutputStream("d:/e.txt"); //获取读取通道 FileChannel inChannel = fileInputStream.getChannel(); //获取写入通道 FileChannel outChannel = fileOutputStream.getChannel(); //完成数据的写入 inChannel.transferTo(0,inChannel.size(),outChannel); } }
2)利用FileChannel 提供的读写方法
package com.troy.nio.application; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class Channel { public static void main(String[] args) throws Exception { //读取文件 FileInputStream fileInputStream = new FileInputStream("d:/t.txt"); //写出文件 FileOutputStream fileOutputStream = new FileOutputStream("d:/e.txt"); //获取读取通道 FileChannel inChannel = fileInputStream.getChannel(); //获取写入通道 FileChannel outChannel = fileOutputStream.getChannel(); //缓存 ByteBuffer byteBuffer = ByteBuffer.allocate(1024); //读取数据 while (inChannel.read(byteBuffer) != -1) { //转换成可读写 byteBuffer.flip(); System.out.println(new String(byteBuffer.array(),"GBK").trim()); //写出数据,清楚缓存 outChannel.write(byteBuffer); byteBuffer.clear(); } } }
四、SocketChannel和ServerSocketChannel在同时使用时,都是tcp协议进行传输的,在使用上面比较服务具体的协议控制
具体的应用可以参考:http://www.cnblogs.com/ll409546297/p/7929646.html
五、DatagramChannel的方式
1)客户端
import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; public class UDPClient { public static void main(String[] args) throws Exception { //获取UDP通道 DatagramChannel datagramChannel = DatagramChannel.open(); //设置非阻塞 datagramChannel.configureBlocking(false); //发送数据 datagramChannel.send(ByteBuffer.wrap("hello server!".getBytes()),new InetSocketAddress("localhost",9000)); } }
2)服务端的2中写法,阻塞和非阻塞
1、阻塞
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; public class UDPServer { //UDP通道 private static DatagramChannel datagramChannel; public static void main(String[] args) throws Exception { serverInit(); listen(); } //初始化 private static void serverInit() throws IOException { //获取UDP通道 datagramChannel = DatagramChannel.open(); //设置接收端口 datagramChannel.socket().bind(new InetSocketAddress(9000)); } //监听 private static void listen() throws IOException { while (true) { //接收的长度 ByteBuffer byteBuffer = ByteBuffer.allocate(1024); //这里会阻塞 datagramChannel.receive(byteBuffer); byteBuffer.flip(); System.out.println(new String(byteBuffer.array()).trim()); } } }
2、非阻塞,利用selector来进行数据选择
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.util.Iterator; public class UDPServer { //选择器 private static Selector selector; //UDP通道 private static DatagramChannel datagramChannel; public static void main(String[] args) throws Exception { serverInit(); listen(); } //初始化 private static void serverInit() throws IOException { //获取选择器 selector = Selector.open(); //获取UDP通道 datagramChannel = DatagramChannel.open(); //设置非阻塞 datagramChannel.configureBlocking(false); //设置接收端口 datagramChannel.socket().bind(new InetSocketAddress(9000)); //注册 datagramChannel.register(selector, SelectionKey.OP_READ); } //监听 private static void listen() throws IOException { while (true) { selector.select(); Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey selectionKey = iterator.next(); if (selectionKey.isReadable()) { //接收的长度 ByteBuffer byteBuffer = ByteBuffer.allocate(1024); //这里不会阻塞 datagramChannel.receive(byteBuffer); byteBuffer.flip(); System.out.println(new String(byteBuffer.array()).trim()); } } } } }
六、基本上channel的实现用法就这些了,但是里面会涉及到很多细节的用法,这个需要自己进一步研究