package com.ilike.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import org.junit.Test;
/**
*
* @author 桑伟东
*
* 一、使用NIO完成网络通信的三个核心
* 1.通道(channel):负责连接
* SelectableChannel
* |–SocketChannel
* |–ServerSocketChannel
* |–DataGramChannel
*
* |Pipe.SinkChannel
* |Pipe.SourceChannel
*
* 2.缓冲区(Buffer):负责数据的存储
*
* 3.选择器(Selector):是SelectableChannel的多路复用器。用于监控SelectableChannel的IO状况
*
*/
public class TestBlockingNio {
//客户端
@Test
public void client() throws IOException{
//1.获取通道
SocketChannel sChannel=SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
FileChannel inChannel=FileChannel.open(Paths.get("a.jpg"), StandardOpenOption.READ);
//2.获取指定大小的缓冲区
ByteBuffer buffer=ByteBuffer.allocate(1024);
//3.读取本地文件,并发送到服务端去
while (inChannel.read(buffer)!=-1) {
buffer.flip();
sChannel.write(buffer);
buffer.clear();
}
//4.关闭通道
inChannel.close();
sChannel.close();
}
//服务端
@Test
public void server() throws IOException{
//1.获取通道
ServerSocketChannel ssChannel=ServerSocketChannel.open();
FileChannel outChannel=FileChannel.open(Paths.get("b.jpg"),StandardOpenOption.WRITE, StandardOpenOption.CREATE);
//2.绑定连接
ssChannel.bind(new InetSocketAddress(9898));
//3.获取客户端连接的通道
SocketChannel socketChannel=ssChannel.accept();
//4.分配指定大小的缓冲区
ByteBuffer buffer=ByteBuffer.allocate(1024);
//5.接受客户端的数据
while (socketChannel.read(buffer)!=-1) {
buffer.flip();
outChannel.write(buffer);
buffer.clear();
}
//6.关闭通道
socketChannel.close();
outChannel.close();
ssChannel.close();
}
}
package com.ilike.nio;
import java.nio.ByteBuffer;
import org.junit.Test;
/**
* Buffer缓冲区
* @author 桑伟东
*
*/
public class TestBuffer {
@Test
public void testByteBuffer3(){
//1.分配直接缓冲区
ByteBuffer buffer=ByteBuffer.allocateDirect(1024);
//2.判断是否是直接缓冲区
System.out.println(buffer.isDirect());
}
@Test
public void testByteBuffer2(){
//1.创建一个容量为1024个字节的缓冲区
ByteBuffer buffer=ByteBuffer.allocate(1024);
String src="abcde";
//2.放入数据
buffer.put(src.getBytes());
//3.切换到读模式
buffer.flip();
byte [] dst=new byte[buffer.limit()];
buffer.get(dst,0,2);
System.out.println(new String(dst));
System.out.println(buffer.position());
//4.标记position的位置
buffer.mark();
//5.再次读取
buffer.get(dst,2,2);
System.out.println(new String(dst,2,2));
System.out.println(buffer.position());
//6.让position回到mark标记的位置
System.out.println("---------------");
//该方法可以让position回到之前mark标记的位置
buffer.reset();
System.out.println(buffer.position());
//7.获取缓冲区中可以操作的数据
if(buffer.hasRemaining()){
//读取可以操作的数据的个数
System.out.println(buffer.remaining());
}
}
@Test
public void testByteBuffer1(){
//1.创建一个容量为1024个字节的缓冲区
ByteBuffer buffer=ByteBuffer.allocate(1024);
String src="abcde";
System.out.println("-----------allocate()----------------");
System.out.println(buffer.position());
System.out.println(buffer.limit());
System.out.println(buffer.capacity());
//2.通过put()写入数据
buffer.put(src.getBytes());
System.out.println("-----------put()----------------");
System.out.println(buffer.position());
System.out.println(buffer.limit());
System.out.println(buffer.capacity());
//3.通过flip()切换到读取数据模式
buffer.flip();
System.out.println("-----------flip()----------------");
System.out.println(buffer.position());
System.out.println(buffer.limit());
System.out.println(buffer.capacity());
//4.通过get()读取数据
byte[] dst=new byte[buffer.limit()];
buffer.get(dst);
System.out.println(new String(dst));
System.out.println("-----------get()----------------");
System.out.println(buffer.position());
System.out.println(buffer.limit());
System.out.println(buffer.capacity());
//5.rewind():可以重复读数据
buffer.rewind();
System.out.println("-----------rewind()----------------");
System.out.println(buffer.position());
System.out.println(buffer.limit());
System.out.println(buffer.capacity());
//6.通过claer()清空缓冲区,但是里面的数据依然存在,只是出于被遗忘状态
buffer.clear();
System.out.println("-----------claer()----------------");
System.out.println(buffer.position());
System.out.println(buffer.limit());
System.out.println(buffer.capacity());
System.out.println((char)buffer.get(0));
}
}
package com.ilike.nio;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Map;
import org.junit.Test;
/**
* 一.通道(channel):用于源节点和目标节点的连接,在java NIO中负责缓冲区中数据的传输
* channel本身不存储数据,因此他需要配合缓冲区来进行数据传输
*
* 二.通道的主要实现类
* FileChannel
* SocketChannel
* SeverSocketChannel
* DataGramChannel
* 三.获取通道
* 1.java针对支持通道的类提供了getChannel()的方法
* 本地IO:
* FileInputStream/FileOutputStream
* RandomAccessFile
* 网络IO: Socket
* SeverSocket
* DataGramSocket
* 2.在jdk1.7中的NIO.2中针对各个静态方法提供了open();
* 3.在jdk1.7中的NIO.2中的files工具类newByteChannel()方法
*
* 四.通道之间的数据传输
* transferFrom();
* transferTo();
*
* 五.分散(Scatter)与聚集(Gather)
* 分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区中去
* 聚集写入(Gathering writes):将多个缓冲区中的数据聚集到通道中
*
* 六.字符集 Charset
* 编码:字符串–>字节数组
* 解码:字节数组–>字符串
*
*
*
* @author 桑伟东
*
*/
public class TestChannel {
//字符集
@Test
public void testCharset2() throws IOException {
Charset charset=Charset.forName("GBK");
//获取编码器
CharsetEncoder ce=charset.newEncoder();
//获取解码器
CharsetDecoder cd=charset.newDecoder();
//创建字符缓冲区
CharBuffer cb=CharBuffer.allocate(1024);
cb.put("桑伟东是工程师");
//切换到读模式
cb.flip();
//进行编码
ByteBuffer bb=ce.encode(cb);
for (int i = 0; i < bb.limit(); i++) {
System.out.println(bb.get());
}
//进行解码
bb.flip();
CharBuffer cb2= cd.decode(bb);
System.out.println(cb2.toString());
}
//字符集
@Test
public void testCharset1() {
//获取java中支持的字符集
Map charsets=Charset.availableCharsets();
for (String key : charsets.keySet()) {
System.out.println(key+":"+charsets.get(key));
}
}
//分散与聚集
@Test
public void testChannel4() throws IOException {
RandomAccessFile raf1=new RandomAccessFile("a.txt", "rw");
//1.获取通道
FileChannel inChannel=raf1.getChannel();
//2.分配指定大小的缓冲区
ByteBuffer buffer1=ByteBuffer.allocate(200);
ByteBuffer buffer2=ByteBuffer.allocate(800);
//3.分散读取
ByteBuffer[] buffers={buffer1,buffer2};
inChannel.read(buffers);
for (ByteBuffer byteBuffer : buffers) {
byteBuffer.flip();
}
System.out.println(new String(buffers[0].array()));
System.out.println(new String(buffers[1].array()));
inChannel.close();
RandomAccessFile raf2=new RandomAccessFile("b.txt", "rw");
//4.获取写入通道
FileChannel outChannel=raf2.getChannel();
//5.聚集写入
outChannel.write(buffers);
outChannel.close();
raf2.close();
raf1.close();
}
//通道之间的数据传输(直接缓冲区)
@Test
public void testChannel3() throws IOException {
//1.获取通道
FileChannel inChannel=FileChannel.open(Paths.get("a.jpg"), StandardOpenOption.READ);
FileChannel outChannel=FileChannel.open(Paths.get("b.jpg"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
//2.传输数据
// inChannel.transferTo(0, inChannel.size(), outChannel);
outChannel.transferFrom(inChannel, 0, inChannel.size());
//3.关闭通道
outChannel.close();
inChannel.close();
}
//2.使用直接缓冲区完成文件的复制(内存映射文件)
@Test
public void testChannel2() throws IOException {
long start=System.currentTimeMillis();
//1.获取通道
FileChannel inChannel=FileChannel.open(Paths.get("a.jpg"), StandardOpenOption.READ);
FileChannel outChannel=FileChannel.open(Paths.get("b.jpg"), StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE);
//2.内存映射文件
MappedByteBuffer inBuffer= inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
MappedByteBuffer outBuffer=outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
//3.直接对缓冲区中的数据进行操作
byte[] dst=new byte[inBuffer.limit()];
inBuffer.get(dst);
outBuffer.put(dst);
outChannel.close();
inChannel.close();
long end=System.currentTimeMillis();
System.out.println("共耗时:"+(end-start));
}
//1.使用通道完成文件的复制(非直接缓冲区)
@Test
public void testChannel1() {
long start=System.currentTimeMillis();
// 1.创建流对象
FileInputStream fis = null;
FileOutputStream fos = null;
// 2.获取通道
FileChannel inChannel = null;
FileChannel outChannel = null;
try {
fis = new FileInputStream("a.jpg");
fos = new FileOutputStream("b.jpg");
inChannel = fis.getChannel();
outChannel = fos.getChannel();
// 3.分配一个指定大小的缓存区
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 4.读写数据
while (inChannel.read(buffer) != -1) {
// 切换到读模式
buffer.flip();
// 将数据放入写通道
outChannel.write(buffer);
// 清空缓冲区
buffer.clear();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
// 5.释放资源
if (outChannel != null) {
try {
outChannel.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (inChannel != null) {
try {
inChannel.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
long end=System.currentTimeMillis();
System.out.println("共耗时:"+(end-start));
}
}
package com.ilike.nio;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Pipe;
import java.nio.channels.Pipe.SinkChannel;
import java.nio.channels.Pipe.SourceChannel;
import org.junit.Test;
public class TestPipe {
@Test
public void test1() throws IOException{
//1.获取通道
Pipe pipe=Pipe.open();
//2.将缓冲区中的数据写入管道
ByteBuffer buffer=ByteBuffer.allocate(1024);
SinkChannel sinkChannel= pipe.sink();
buffer.put("通过单向管道发送数据!!!".getBytes());
buffer.flip();
sinkChannel.write(buffer);
//3.读取数据
SourceChannel sourceChannel= pipe.source();
ByteBuffer buffer2=ByteBuffer.allocate(1024);
int len=sourceChannel.read(buffer2);
buffer2.flip();
System.out.println(new String(buffer2.array(),0,len));
sourceChannel.close();
sinkChannel.close();
}
}
package com.ilike.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import org.junit.Test;
public class TestBlockingNio2 {
/**
* 客户端
* @throws IOException
*/
@Test
public void client() throws IOException {
//1.获取通道
SocketChannel sChannel=SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
FileChannel fChannel=FileChannel.open(Paths.get("a.jpg"), StandardOpenOption.READ);
//2.分配指定大小的缓冲区
ByteBuffer buffer=ByteBuffer.allocate(1024);
//3.读取数据发送到服务器
while (fChannel.read(buffer)!=-1) {
buffer.flip();
sChannel.write(buffer);
buffer.clear();
}
sChannel.shutdownOutput();
//4.获取服务端的反馈
int len=0;
while ((len=sChannel.read(buffer))!=-1) {
buffer.flip();
System.out.println(new String(buffer.array(),0, len));
buffer.clear();
}
//5.关闭资源
fChannel.close();
sChannel.close();
}
/**
* 服务端
* @throws IOException
*/
@Test
public void server() throws IOException {
//1.获取通道
ServerSocketChannel ssChannel=ServerSocketChannel.open();
FileChannel outChannel=FileChannel.open(Paths.get("b.jpg"), StandardOpenOption.CREATE, StandardOpenOption.WRITE);
ssChannel.bind(new InetSocketAddress(9898));
//2.与客户端建立连接
SocketChannel sChannel=ssChannel.accept();
//3.分配指定大小的缓冲区
ByteBuffer buffer=ByteBuffer.allocate(1024);
//4.读取客户端的数据
while (sChannel.read(buffer)!=-1) {
buffer.flip();
outChannel.write(buffer);
buffer.clear();
}
//5.给客户端给一个成功的消息
buffer.put("成功".getBytes());
buffer.flip();
sChannel.write(buffer);
//6.关闭通道
sChannel.close();
outChannel.close();
ssChannel.close();
}
}
package com.ilike.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Iterator;
import java.util.Scanner;
import org.junit.Test;
/**
*
* @author 桑伟东
*
* 一、使用NIO完成网络通信的三个核心
* 1.通道(channel):负责连接
* SelectableChannel
* |–SocketChannel
* |–ServerSocketChannel
* |–DataGramChannel
*
* |Pipe.SinkChannel
* |Pipe.SourceChannel
*
* 2.缓冲区(Buffer):负责数据的存储
*
* 3.选择器(Selector):是SelectableChannel的多路复用器。用于监控SelectableChannel的IO状况
*
*/
public class TestNonBlockingNio {
/**
* 客户端
* @throws IOException
*/
@Test
public void client() throws IOException {
//1.获取通道
SocketChannel sChannel=SocketChannel.open(new InetSocketAddress(“127.0.0.1”, 9898));
//2.切换到非阻塞模式
sChannel.configureBlocking(false);
//3.分配指定大小的缓冲区
ByteBuffer buffer=ByteBuffer.allocate(1024);
//4.发送数据
Scanner sc=new Scanner(System.in);
while (sc.hasNext()) {
buffer.put((new Date().toString()+”\n”+sc.nextLine()).getBytes());
buffer.flip();
sChannel.write(buffer);
buffer.clear();
}
//5.关闭通道
sChannel.close();
}
/**
* 服务端
* @throws IOException
*/
@Test
public void server() throws IOException {
//1.获取通道
ServerSocketChannel ssChannel=ServerSocketChannel.open();
//2.切换到非阻塞模式
ssChannel.configureBlocking(false);
//3.绑定连接
ssChannel.bind(new InetSocketAddress(9898));
//4.获取选择器
Selector selector=Selector.open();
//5.将通道注册到选择器上,并且指定监听接受事件
ssChannel.register(selector, SelectionKey.OP_ACCEPT);
//6.轮询的获取选择器上已经“准备就绪”的事件
while (selector.select()>0) {
//7.获取当前选择器中所有注册的“选择键”(已就绪的监听事件)
Iterator it=selector.selectedKeys().iterator();
while (it.hasNext()) {
//8.获取准备就绪的事件
SelectionKey sk=it.next();
//9.判断准备就绪的是什么事件
if(sk.isAcceptable()){
//10.若接收状态就绪,获取客户端的连接
SocketChannel sChannel=ssChannel.accept();
//11.切换到非阻塞模式
sChannel.configureBlocking(false);
//12.将该通道注册到选择器上
sChannel.register(selector, SelectionKey.OP_READ);
}else if(sk.isReadable()){
//13.获取当前选择器上“读就绪”的通道
SocketChannel readChannel=(SocketChannel) sk.channel();
//14.读取数据
ByteBuffer buffer=ByteBuffer.allocate(1024);
int len=0;
while ((len=readChannel.read(buffer))>0) {
buffer.flip();
System.out.println(new String(buffer.array(),0,len));
buffer.clear();
}
}
//15.取消选择键SelectionKey
it.remove();
}
}
}
}
package com.ilike.nio;
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.Date;
import java.util.Iterator;
import java.util.Scanner;
import org.junit.Test;
public class TestNonBlockingNio2 {
@Test
public void send() throws IOException {
//1.获取通道
DatagramChannel dc=DatagramChannel.open();
//2.切换到非阻塞模式
dc.configureBlocking(false);
//3.分配指定大小的缓冲区
ByteBuffer buffer=ByteBuffer.allocate(1024);
//4.发送数据
Scanner sc=new Scanner(System.in);
while (sc.hasNext()) {
buffer.put((new Date().toString()+":\n"+sc.nextLine()).getBytes());
buffer.flip();
dc.send(buffer, new InetSocketAddress("127.0.0.1", 9898));
buffer.clear();
}
//5.关闭通道
dc.close();
}
@Test
public void receive() throws IOException {
//1.获取通道
DatagramChannel dc=DatagramChannel.open();
//2.切换到非阻塞模式
dc.configureBlocking(false);
//3.绑定端口号
dc.bind(new InetSocketAddress(9898));
//4.获取选择器
Selector selector=Selector.open();
//5.将该通道注册在这个选择器上
dc.register(selector, SelectionKey.OP_READ);
while (selector.select()>0) {
Iterator it=selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey sk=it.next();
if(sk.isReadable()){
ByteBuffer buffer=ByteBuffer.allocate(1024);
dc.receive(buffer);
buffer.flip();
System.out.println(new String(buffer.array(),0,buffer.limit()));
buffer.clear();
}
}
it.remove();
}
}
}