java nio 写事件,Java NIO那点事

什么是NIO?

New Input/Output

基于通道和缓冲区的I/O方式

可使用Native函数库直接分配堆外内存

通过存储于Java堆的DirectByteBuffer对象直接操作已分配的堆外内存

同步非阻塞模型

同步是指不间断轮询IO是否就绪

核心是Selector

Selector代替了线程本身轮询IO事件,避免了阻塞,同时避免了不必要的线程消耗(如线程等待)

非阻塞是指,等待IO过程中,可以同时做其他任务

核心是通道和缓冲区

IO就绪时,通过通道写入缓冲区保证IO成功,无需阻塞等待

与传统IO区别

传统IO面向流,NIO面向缓冲区

传统IO是阻塞式的,NIO是非阻塞的

几个重要概念

Buffer 缓冲区

ByteBuffer

CharBuffer

DoubleBuffer

FloatBuffer

IntBuffer

LongBuffer

ShortBuffer

Channel 通道

SocketChannel

ServerSocketChannel

FileChannel

DatagramChannel

Selector 选择器

监管IO事件

Channel注册到Selector

单线程处理多个Channel

实例说事(干货)

FileChannel

package com.abuge.nio.demo;

import java.io.BufferedInputStream;

import java.io.FileInputStream;

import java.io.InputStream;

import java.nio.ByteBuffer;

import java.nio.channels.FileChannel;

/**

* Created by huxianyang on 2017/6/15.

*/

public class FileChannelDemo {

public static void main(String[] args) {

normalIOReadFile();

nioReadFile();

}

private static void normalIOReadFile() {

System.out.println("-----------------start to read file by normal IO-----------------");

try (InputStream in = new BufferedInputStream(new FileInputStream("src/com/abuge/nio/resource/normal_io.txt"))) {

byte[] buffer = new byte[1024];

int byteNum = in.read(buffer);

while (-1 != byteNum) {

for (int i = 0; i < byteNum; i++) {

System.out.print((char) buffer[i]);

}

byteNum = in.read(buffer);

}

} catch (Exception e) {

e.printStackTrace();

}

System.out.println("-----------------end to read file by normal IO-----------------");

}

private static void nioReadFile() {

System.out.println("-----------------start to read file by NIO-----------------");

try(FileChannel fileChannel = new FileInputStream("src/com/abuge/nio/resource/nio.txt").getChannel()) {

ByteBuffer buffer = ByteBuffer.allocate(1024);

int byteReadNum = fileChannel.read(buffer);

System.out.println("read file byte is " + byteReadNum);

while(-1 != byteReadNum){

buffer.flip();

while (buffer.hasRemaining()){

System.out.print((char)buffer.get());

}

buffer.compact();

byteReadNum = fileChannel.read(buffer);

}

}catch (Exception e){

e.printStackTrace();

}

System.out.println("-----------------end to read file by NIO-----------------");

}

}

SocketChannel

客户端使用NIO,使用非阻塞模式发送数据

服务端使用IO,阻塞接收数据

package com.abuge.nio.demo;

import java.io.IOException;

import java.io.InputStream;

import java.net.InetSocketAddress;

import java.net.ServerSocket;

import java.net.Socket;

import java.net.SocketAddress;

import java.nio.ByteBuffer;

import java.nio.channels.SocketChannel;

import java.util.concurrent.TimeUnit;

/**

* Created by huxianyang on 2017/6/16.

*/

public class SocketChannelDemo {

public static void main(String[] args) {

sendByNIO();

}

private static void sendByNIO() {

try (SocketChannel socketChannel = SocketChannel.open()) {

socketChannel.configureBlocking(false);

System.out.println("------------- start to connect server -------------");

boolean connect = socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080));

System.out.println("--------------connect is " + connect + "------------");

ByteBuffer buffer = ByteBuffer.allocate(1024);

if (socketChannel.finishConnect()) {

System.out.println("------------- connect successful -------------");

int i = 0;

while (true) {

TimeUnit.SECONDS.sleep(1);

String info = "I'm " + (i++) + "-th information from client.";

buffer.clear();

buffer.put(info.getBytes());

buffer.flip();

while (buffer.hasRemaining()) {

System.out.println("client send " + buffer);

socketChannel.write(buffer);

}

}

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

package com.abuge.nio.demo;

import java.io.IOException;

import java.io.InputStream;

import java.net.ServerSocket;

import java.net.Socket;

import java.net.SocketAddress;

/**

* Created by huxianyang on 2017/6/16.

*/

public class ServerSocketDemo {

public static void main(String[] args){

acceptByIO();

}

private static void acceptByIO() {

InputStream in = null;

try (ServerSocket serverSocket = new ServerSocket(8080);) {

byte[] buffer = new byte[1024];

int recvMsgSize = 0;

while (true) {

System.out.println("------------- start to receive msg -------------");

Socket clientSocket = serverSocket.accept();

SocketAddress clientAddress = clientSocket.getRemoteSocketAddress();

System.out.println("handling client at " + clientAddress);

in = clientSocket.getInputStream();

while (-1 != (recvMsgSize = in.read(buffer))) {

byte[] tmp = new byte[recvMsgSize];

System.arraycopy(buffer, 0, tmp, 0, recvMsgSize);

System.out.println(new String(buffer));

}

}

} catch (Exception e) {

e.printStackTrace();

} finally {

if (null != in) {

try {

in.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

}

服务端的NIO写法

ServerSocketChannel

Selector

package com.abuge.nio.demo;

import java.io.IOException;

import java.net.InetSocketAddress;

import java.nio.ByteBuffer;

import java.nio.channels.*;

import java.util.Iterator;

/**

* Created by huxianyang on 2017/6/19.

*/

public class ServerConnect {

private static final int PORT = 8090;

private static final int TIMEOUT = 3000;

private static final int BUF_SIZE = 1024;

public static void main(String[] arsg) {

selector();

}

private static void selector() {

System.out.println("-------------------start to execute select-------------------");

try (Selector selector = Selector.open(); ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();) {

serverSocketChannel.socket().bind(new InetSocketAddress(PORT));

serverSocketChannel.configureBlocking(false);

serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);//表示此通道关注的是连接事件,有连接事件时,selector触发通道执行操作

while (true) {

if (0 == selector.select(TIMEOUT)) {

System.out.println("============there is no channel is ready to execute IO operations============");

continue;

}

Iterator iterator = selector.selectedKeys().iterator();

int i = 0;

while (iterator.hasNext()) {

SelectionKey key = iterator.next();

if (key.isAcceptable()) {//表示此key对应的通道可以接收连接

System.out.println("============the key represent channel is acceptable============ " + i);

handleAccept(key);//将通道置为了关注读就绪事件

}

if (key.isReadable()) {//表示此key对应的通道可以接收读数据

System.out.println("============the key represent channel is readable============" + (i++));

handleRead(key);

}

if (key.isWritable()) {//表示此key对应的通道可以接收读数据

System.out.println("============the key represent channel is writable============");

handleWrite(key);

}

if (key.isConnectable()) {//表示连接就绪,通常用于client端请求建立连接时

System.out.println("============the key represent channel is connectable============");

}

iterator.remove();

}

}

} catch (Exception e) {

e.printStackTrace();

}

System.out.println("-------------------end to execute select-------------------");

}

private static void handleWrite(SelectionKey key) throws IOException {

SocketChannel socketChannel = (SocketChannel) key.channel();

ByteBuffer buf = (ByteBuffer) key.attachment();

buf.flip();

while (buf.hasRemaining()) {

socketChannel.write(buf);

System.out.print((char) buf.get());

}

buf.compact();

}

private static void handleRead(SelectionKey key) throws IOException {

SocketChannel socketChannel = (SocketChannel) key.channel();

ByteBuffer buf = (ByteBuffer) key.attachment();

int bytesRead = socketChannel.read(buf);

while (0 < bytesRead) {

buf.flip();

while (buf.hasRemaining()) {

System.out.print((char) buf.get());

}

System.out.println("====================================");

buf.clear();

bytesRead = socketChannel.read(buf);

if (-1 == bytesRead) {

socketChannel.close();

}

}

}

private static void handleAccept(SelectionKey key) throws IOException {

ServerSocketChannel serverSocketcChannel = (ServerSocketChannel) key.channel();

SocketChannel socketChannel = serverSocketcChannel.accept();

socketChannel.configureBlocking(false);

socketChannel.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(BUF_SIZE));

}

}

PS:Idea常用快捷键

Ctrl + Q 查看注释

Ctrl + N 查找类

双击Shift 查找Everything

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值