NIO也就是非堵塞的IO径玖,通過Selector來注冊(cè)事件,用死循環(huán)來不斷輪詢被注冊(cè)的通道纪挎,一旦有某個(gè)通道符合條件期贫,就會(huì)被挑選出來到selectedKeys中進(jìn)行處理,處理完畢后要把selectedKeys清空异袄,進(jìn)入到下次輪詢通砍。
NIO十分高效,節(jié)省服務(wù)器的資源
下面是NIO的服務(wù)器端
package nio;
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.Iterator;
public class MyServer {
public static void main(String[] args) throws Exception {
ByteBuffer buffer = ByteBuffer.allocate(1024);
* 開啟挑選器
Selector sel = Selector.open();
* 開啟ServerSocket通道
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.socket().bind(new InetSocketAddress("localhost", 8888));
* 設(shè)置非堵塞模式烤蜕,默認(rèn)是堵塞
ssc.configureBlocking(false);
* 在挑選器中注冊(cè)通道(服務(wù)器通道)
ssc.register(sel, SelectionKey.OP_ACCEPT);
while(true) {
* 該方法是堵塞的封孙,只有選擇到key才會(huì)向下執(zhí)行
sel.select();
Iterator<SelectionKey> it = sel.selectedKeys().iterator();
while(it.hasNext()) {
SelectionKey key = it.next();
* 有通道,接收并注冊(cè)
if(key.isAcceptable()) {
System.out.println("當(dāng)前的的selector:" + key + ", 有連接進(jìn)來了");
ServerSocketChannel sc = (ServerSocketChannel) key.channel();
SocketChannel sc0 = sc.accept();
* 設(shè)置SocketChannel為非堵塞
sc0.configureBlocking(false);
* 注冊(cè)讀事件
sc0.register(sel, SelectionKey.OP_READ);
}
if(key.isReadable()) {
System.out.println("當(dāng)前的的selector:" + key + ", 讀取數(shù)據(jù)事件");
SocketChannel sc1 = (SocketChannel) key.channel();
* 回送hello:
byte[] helloByte = "hello:".getBytes();
buffer.put(helloByte, 0, helloByte.length);
while(sc1.read(buffer) != 0) {
buffer.flip();
sc1.write(buffer);
buffer.clear();
}
}
sel.selectedKeys().clear();
}
}
}
}
客戶端(使用一般的socket處理數(shù)據(jù)也是可以的)
package nio;
import java.io.ByteArrayOutputStream;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
public class MyClient {
public static void main(String[] args) throws Exception {
Selector sel = Selector.open();
SocketChannel sc = SocketChannel.open();
sc.connect(new InetSocketAddress("localhost", 8888));
sc.configureBlocking(false);
sc.register(sel, SelectionKey.OP_READ);
ByteBuffer buffer = ByteBuffer.allocate(8 * 1024);
buffer.put("everything will be good".getBytes());
buffer.flip();
sc.write(buffer);
buffer.clear();
while(true) {
sel.select();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while(sc.read(buffer) > 0) {
buffer.flip();
baos.write(buffer.array(), 0, buffer.limit());
buffer.clear();
}
baos.close();
System.out.println(new String(baos.toByteArray()));
sel.selectedKeys().clear();
}
}
}
文件通道ByteBuffer
Buffer
1.mark讽营,記號(hào)虎忌,(reset)
2.position,當(dāng)前指針位置索引值
3.limit,限制橱鹏,可以使用的數(shù)組長(zhǎng)度膜蠢,從開始計(jì)算
4.capactiy,容量莉兰,是數(shù)組的長(zhǎng)度挑围。
約束條件
0 <= mark <= pos <= limit <= capacity
ByteBuffer
flip() 拍板,
package TestCase;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import org.junit.Test;
public class TestFileChannel {
* 利用文件通道來復(fù)制文件
@Test
public void test1() throws Exception {
* 輸入
FileInputStream fis = new FileInputStream("E://TestCase//day24//demo.jpg");
* 獲得文件通道
FileChannel fcIn = fis.getChannel();
FileOutputStream fos = new FileOutputStream("E://TestCase//day24//demo2.jpg");
FileChannel fcOut = fos.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024*8);
while(fcIn.read(buffer) != -1) {
buffer.flip();
fcOut.write(buffer);
buffer.clear();
}
fcIn.close();
fcOut.close();
}
* 將文件讀取到內(nèi)存中
@Test
public void test2() throws Exception {
File f = new File("E://TestCase//day24//demo.jpg");
RandomAccessFile raf = new RandomAccessFile(f, "rw");
MappedByteBuffer buffer = raf.getChannel().map(MapMode.READ_ONLY, 1, 100);
System.out.println(buffer.get(0));
System.out.println(buffer.capacity());
raf.close();
}
* 測(cè)試離堆內(nèi)存
@Test
public void test3() throws Exception{
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
Class clazz = Class.forName("java.nio.DirectByteBuffer");
Field f = clazz.getDeclaredField("cleaner");
f.setAccessible(true);
Object cleaner = f.get(buffer);
System.out.println(cleaner);
Class clazz2 = Class.forName("java.lang.ref.Cleaner");
Method m = clazz2.getDeclaredMethod("clean", null);
m.invoke(cleaner, null);
System.out.println("end");
}
}