NIO --> New IO,提供了非阻塞模型(No -Blocked IO)
NIO这块参考文章:
同步非阻塞
Server端
public class MyNewIOServer {
public static void main(String[] args) {
try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);//设置为非阻塞(非阻塞IO默认是阻塞的,需要这样设置一下才生效)
serverSocketChannel.socket().bind(new InetSocketAddress(8080));
while (true){
SocketChannel socketChannel = serverSocketChannel.accept();//监听客户端请求
if(socketChannel != null){
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);//分配缓冲区的大小
socketChannel.read(byteBuffer);//把数据读取到缓冲区
System.out.println(new String(byteBuffer.array()));
//写出数据
byteBuffer.flip();//反转
socketChannel.write(byteBuffer);//写出去
}else{
//连接不阻塞,没有发现客户端有请求过来,睡眠一下,再次重试。
Thread.sleep(1000);
System.out.println("连接未就绪");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Client端:
public class MyNewIOClient {
public static void main(String[] args) {
try {
SocketChannel socketChannel = SocketChannel.open();
// socketChannel.configureBlocking(false);//这里同样也要设置成 非阻塞
socketChannel.connect(new InetSocketAddress("localhost",8080));
/**
* 如果SocketChannel在非阻塞模式下【设置的socketChannel.configureBlocking(false)】,
* 此时调用connect(),该方法可能在连接建立之前就返回了.
* 为了确定连接是否建立,可以调用finishConnect()的方法
*/
if(socketChannel.isConnectionPending()){
socketChannel.finishConnect();//与服务端建立连接(返回true,表示与服务端连接成功)
}
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
byteBuffer.put("Hello,我是小风".getBytes());
byteBuffer.flip();
socketChannel.write(byteBuffer);
//读取数据
byteBuffer.clear();//先清空一下缓冲区
// Thread.sleep(2000); 如果设置了socketChannel.configureBlocking(false);,下面的read就读不到数据,这里可以增加2s的停顿时间,下面就读取到了
int i = socketChannel.read(byteBuffer);//把服务端返回的数据读到缓冲区
//注释:read()方法返回的int值表示读了多少字节进Buffer里。如果返回的是-1,表示已经读到了流的末尾(连接关闭了)
if(i > 0){ //收到数据
System.out.println("收到了服务端的数据" + new String(byteBuffer.array()));
}else{
System.out.println("没有收到数据");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
以上代码没有用 Selector(多路复用器),其实有很大的性能消耗...
多路复用
Selector是多路复用器
** 下面使用Selector重构 **
Server端
public class NewIoServer {
static Selector selector;
public static void main(String[] args) {
try {
selector=Selector.open();
//selector 必须是非阻塞
ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false); //设置为非阻塞
serverSocketChannel.socket().bind(new InetSocketAddress(8080));
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); //每个客户端连接来了之后,就把连接事件注册到多路复用器上
while(true){
selector.select(); //阻塞机制
Set<SelectionKey> selectionKeySet=selector.selectedKeys();
Iterator<SelectionKey> iterable=selectionKeySet.iterator();
while(iterable.hasNext()){
SelectionKey key=iterable.next();
iterable.remove();
if(key.isAcceptable()){ //连接事件。默认初始状态就是acceptable。
handleAccept(key);
}else if(key.isReadable()){ //读的就绪事件
handleRead(key);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void handleAccept(SelectionKey selectionKey){
ServerSocketChannel serverSocketChannel=(ServerSocketChannel) selectionKey.channel();
try {
SocketChannel socketChannel=serverSocketChannel.accept() ;//这个是客户端的socketChannel
System.out.println("客户端的channel来源:"+socketChannel.getRemoteAddress());
socketChannel.configureBlocking(false);
socketChannel.write(ByteBuffer.wrap("Hello Client,I'm NIO Server".getBytes()));
socketChannel.register(selector,SelectionKey.OP_READ); //注册读事件
} catch (IOException e) {
e.printStackTrace();
}
}
private static void handleRead(SelectionKey selectionKey){
SocketChannel socketChannel=(SocketChannel)selectionKey.channel();
ByteBuffer byteBuffer=ByteBuffer.allocate(1024);//分配缓冲区大小
try {
//数据的交互是以buffer为中间桥梁的
//如果要读取,先把数据读到buffer里,然后再进行打印
socketChannel.read(byteBuffer); //把数据读取到缓冲区(这里是不是一定有值)
//打印
System.out.println("server receive msg:"+new String(byteBuffer.array()));
//如果要返回数据的话,先把数据返回到buffer里,然后再返回出去
String res = "这里是服务端获取的数据12345";
channel.write(ByteBuffer.wrap(res.getBytes()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client端
public class NewIOClient {
static Selector selector;
public static void main(String[] args) {
try {
selector=Selector.open();
SocketChannel socketChannel=SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("localhost",8080));
socketChannel.register(selector, SelectionKey.OP_CONNECT); //连接事件
while(true){
selector.select();
Set<SelectionKey> selectionKeySet=selector.selectedKeys();
Iterator<SelectionKey> iterator=selectionKeySet.iterator();
while(iterator.hasNext()){
SelectionKey key=iterator.next();
iterator.remove();
if(key.isConnectable()){ //连接事件
handleConnect(key);
}else if(key.isReadable()){
handleRead(key);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void handleConnect(SelectionKey selectionKey) throws IOException {
SocketChannel socketChannel=(SocketChannel)selectionKey.channel();
if(socketChannel.isConnectionPending()){
socketChannel.finishConnect();
}
socketChannel.configureBlocking(false);
socketChannel.write(ByteBuffer.wrap("Hello Server,I'm NIo Client".getBytes()));
socketChannel.register(selector,SelectionKey.OP_READ); //
}
private static void handleRead(SelectionKey selectionKey) throws IOException {
SocketChannel socketChannel=(SocketChannel)selectionKey.channel();
ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
socketChannel.read(byteBuffer);
System.out.println("client receive msg:"+new String(byteBuffer.array()));
}
}