Java NIO Buffer Channel Selector
阿新 • • 發佈:2019-02-10
1、緩衝區型別:
ByteBuffer
CharBuffer
ShortBufer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer,並沒有 BooleanBuffer
2、ByteBuffer 基本操作
import java.nio.ByteBuffer; public class MainNioTest { public static void main(String[] args) { //初始化 ByteBuffer buffer = ByteBuffer.allocate(10); //儲存 buffer.put("1234567".getBytes()); //反轉(讀寫轉換) buffer.flip(); //讀取 while (buffer.hasRemaining()) { System.out.print((char)buffer.get()); } } }
3、ByteBuffer 繼承類
HeapByteBuffer 分配在jvm堆記憶體
DirectByteBuffer 直接分配在記憶體
DirectByteBufferR 返回只一個只讀物件,無法寫操作
MappedByteBuffer 大檔案操作
4、Channel通道型別
FileChannel:從檔案中讀寫資料 DatagramChannel:能通過UDP讀寫網路中的資料。 SocketChannel:能通過TCP讀寫網路中的資料。 ServerSocketChannel:可以監聽新進來的TCP連線,像Web伺服器那樣。對每一個新進來的連線都會建立一個SocketChannel
5、Buffer和Channel
import java.io.File; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class MainNIoChannel { public static void main(String[] args) throws Exception { String path = "D:"+File.separator+"data.txt"; RandomAccessFile aFile = new RandomAccessFile(path,"rw"); FileChannel channel = aFile.getChannel();//得到管道 //藉助一個Buffer來與Channel進行互動 ByteBuffer buffer = ByteBuffer.allocate(1025); int readByteLen; while((readByteLen = channel.read(buffer)) != -1){ System.out.println("讀取到buffer中的資料長度為:"+readByteLen); System.out.println("內容如下:"); //將Buffer從寫模式切換到讀模式 buffer.flip(); while(buffer.hasRemaining()){ System.out.print((char)buffer.get()); } buffer.clear(); System.out.println();//換行 } aFile.close(); } }
6、Selector
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.Iterator;
import java.util.Set;
public class MainSelectorServer {
public static void main(String[] args) throws Exception {
MainSelectorServer server = new MainSelectorServer();
server.init(9999);
server.listen();
}
// 通道選擇器
private Selector selector;
public MainSelectorServer(){
try {
selector = Selector.open();
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* 函式功能:伺服器端開始監聽,看是否有客戶端連線進來
*/
private void listen() throws Exception {
System.out.println("server running....");
while (true) {
// 當註冊事件到達時,方法返回,否則該方法會一直阻塞
selector.select();
// 獲得selector中選中的相的迭代器,選中的相為註冊的事件
Set<SelectionKey> set = selector.selectedKeys();
Iterator<SelectionKey> ite = set.iterator();
while (ite.hasNext()) {
SelectionKey selectionKey = (SelectionKey) ite.next();
// 刪除已選的key 以防重負處理
ite.remove();
if (selectionKey.isAcceptable()) {// 如果有客戶端連線進來
// 先拿到這個SelectionKey裡面的ServerSocketChannel。
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel = serverSocketChannel.accept();
System.out.println("有客戶端連線到伺服器!!!");
socketChannel.configureBlocking(false);// 將此通道設定為非阻塞
Thread.sleep(2000);
socketChannel.write(ByteBuffer.wrap(new String("hello client!").getBytes()));
socketChannel.register(selector, SelectionKey.OP_READ);
} else if (selectionKey.isReadable()) {// 客戶端傳送資料過來了
// 先拿到這個SelectionKey裡面的SocketChannel。
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
// 接收來自於客戶端傳送過來的資料
ByteBuffer buf = ByteBuffer.allocate(13);
while (socketChannel.read(buf) != -1) {
byte[] receData = buf.array();
String msg = new String(receData).trim();
Thread.sleep(2000);
System.out.println("接收來自客戶端的資料為:" + msg);
buf.clear();
}
}
}
}
}
/*
* 函式功能:初始化serverSocketChannel來監聽指定的埠是否有新的TCP連線,
* 並將serverSocketChannel註冊到selector中
*/
private void init(int port) {
try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// serverSocketChannel監聽指定埠
serverSocketChannel.socket().bind(new InetSocketAddress(port));
serverSocketChannel.configureBlocking(false);// 設定為非阻塞模式
// 將serverSocketChannel註冊到selector中,併為該通道註冊selectionKey.OP_ACCEPT事件
// 註冊該事件後,當事件到達的時候,selector.select()會返回, 如果事件沒有到達selector.select()會一直阻塞
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (IOException e) {
e.printStackTrace();
}
}
}
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.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class MainSelectorClient {
public static void main(String[] args) throws Exception {
MainSelectorClient client = new MainSelectorClient();
client.init("localhost", 9999);
client.connect();
}
private Selector selector;
public MainSelectorClient() throws IOException {
this.selector = Selector.open();
}
private void init(String address, int port) throws IOException {
// 客戶端,首先有一個SocketChannel
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);// 將此通道設定為非阻塞模式
socketChannel.connect(new InetSocketAddress(address, port));
// 將SocketChannel註冊到selector中,併為該通道註冊SelectionKey.OP_CONNECT
socketChannel.register(selector, SelectionKey.OP_CONNECT);
}
private void connect() throws Exception {
while (true) {
selector.select();
Set<SelectionKey> set = selector.selectedKeys();
Iterator<SelectionKey> ite = set.iterator();
while (ite.hasNext()) {
SelectionKey selectionKey = (SelectionKey) ite.next();
ite.remove(); // 刪除已選的key,以防重複處理
if (selectionKey.isConnectable()) {// 看是否有連線發生
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
// 如果正在連線,則完成連線
if (socketChannel.isConnectionPending()) {
socketChannel.finishConnect();
}
socketChannel.configureBlocking(false);// 設定為非阻塞模式
// 給伺服器端傳送資料
System.out.println("客戶端連線上了伺服器端。。。。");
Thread.sleep(2000);
socketChannel.write(ByteBuffer.wrap(new String("hello server!").getBytes()));
// 為了接收來自伺服器端的資料,將此通道註冊到選擇器中
socketChannel.register(selector, SelectionKey.OP_READ);
} else if (selectionKey.isReadable()) {
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
// 接收來自於伺服器端傳送過來的資料
ByteBuffer buf = ByteBuffer.allocate(13);
while (socketChannel.read(buf) != -1) {
byte[] receData = buf.array();
String msg = new String(receData).trim();
Thread.sleep(2000);
System.out.println("接收來自伺服器端的資料為:" + msg);
buf.clear();
}
}
}
}
}
}