接前面的一节。
上面一节主要说得是基本知识。主要的传输是本地的。filechannel.。 也谈不上什么阻塞非阻塞。 这一节说说阻塞非阻塞,主要是网络传输,客户端服务端访问之类。
-----------------------------------------------------------------------------------
1.单线程阻塞--->多线程----->选择器
-----------
练习:
----1.TestBlockingNIO.java----- 这个是阻塞的,没有选择器监听------------------
package com.fjf.study;
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;
/**
* 先练习一个 阻塞式的Nio
* @author fjf
* 2017年11月27日 18:40:01
*
* 自我理解 channel.read() 是数据读到buff上。channel.write() 数据从buff写到通道中,以buff作为中心
*/
public class TestBlockingNIO {
//客户端
@Test
public void client() throws IOException{
//1.获取网络通道
SocketChannel schannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 5858));
//2.准备数据,(获取file通道,装buff,将内容弄到网络通道中)
FileChannel incChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
ByteBuffer buff = ByteBuffer.allocate(1024);
while(incChannel.read(buff)!=-1){
buff.flip();
schannel.write(buff);
buff.clear();
}
/*schannel.shutdownOutput();
//加点料 接受服务端的反馈
int len = 0;
while((len = schannel.read(buff))!=-1){
buff.flip();
System.out.println(new String(buff.array(),0,len));
buff.clear();
}
//System.out.println("------客户端关闭");*/
//3.关闭
schannel.close();
incChannel.close();
}
//服务端
@Test
public void server() throws IOException{
//1.获取网络通道
ServerSocketChannel schannel = ServerSocketChannel.open();
//2.绑定连接
schannel.bind(new InetSocketAddress(5858));
//3.获取客户端通道
SocketChannel clientchannel = schannel.accept();
//4.把客户端通道的数据读到服务端本地
ByteBuffer buff = ByteBuffer.allocate(1024);
FileChannel outcChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE,StandardOpenOption.CREATE);
while(clientchannel.read(buff)!=-1){
buff.flip();
outcChannel.write(buff);
buff.clear();
}
System.out.println("服务端啦啦啦");
//加点料,给客户端点反馈
/*buff.put(("服务端解接受成功").getBytes());
buff.flip();
clientchannel.write(buff);*/
//5.关闭
schannel.close();
clientchannel.close();
outcChannel.close();
}
}
--------2.TestNonBlockingNIO.java--------------非阻塞--
package com.fjf.study;
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.Date;
import java.util.Iterator;
import org.junit.Test;
/**
* 非阻塞io channel ,buffer,selector
* @author fjf
* 如果工作中用到了,一般就是用的这个
* 2017年11月28日 17:51:22
*/
public class TestNonBlockingNIO {
//客户端
@Test
public void client() throws IOException{
//1.获取网络通道
SocketChannel schannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 6868));
//2.通道切换为非阻塞模式
schannel.configureBlocking(false);
//3.指定buff
ByteBuffer buff = ByteBuffer.allocate(1024);
//4.写入数据
buff.put(new Date().toString().getBytes());
buff.flip();
schannel.write(buff);
buff.clear();
//5.关闭
schannel.close();
}
//服务端
@Test
public void server() throws IOException{
//1.获取网络通道
ServerSocketChannel sschannel = ServerSocketChannel.open();
//2. 切换为非阻塞模式
sschannel.configureBlocking(false);
//3. 绑定连接
sschannel.bind(new InetSocketAddress(6868));
//4. 新建选择器
Selector selector= Selector.open();
//5. 注册通道,并设置监听事件
sschannel.register(selector, SelectionKey.OP_ACCEPT);
//6. 轮询获取已注册的所有选择器
while(selector.select()>0){
Iterator<SelectionKey> it= selector.selectedKeys().iterator();
while(it.hasNext()){
SelectionKey sk = it.next();
if(sk.isAcceptable()){
SocketChannel clinetchannel = sschannel.accept();
clinetchannel.configureBlocking(false);
clinetchannel.register(selector, SelectionKey.OP_READ);
}else if(sk.isReadable()){
SocketChannel schannel =(SocketChannel) sk.channel();
ByteBuffer buff = ByteBuffer.allocate(512);
int len = 0;
while((len =schannel.read(buff))!=-1){
buff.flip();
System.out.println(new String(buff.array(),0,len));
buff.clear();
}
}
it.remove();
}
}
}
}
---------------------------
总结:
一、使用 NIO 完成网络通信的三个核心:
1. 通道(Channel):负责连接
java.nio.channels.Channel 接口:
|--SelectableChannel
|--SocketChannel
|--ServerSocketChannel
|--DatagramChannel
|--Pipe.SinkChannel
|--Pipe.SourceChannel
2. 缓冲区(Buffer):负责数据的存取
3. 选择器(Selector):是 SelectableChannel 的多路复用器。用于监控 SelectableChannel 的 IO 状况