服務端:
public class NoBlockServer {
public static void main(String[] args) throws IOException {
// 1.獲取通道
ServerSocketChannel server = ServerSocketChannel.open();
// 2.切換成非阻塞模式
server.configureBlocking(false);
// 3. 繫結連線
server.bind(new InetSocketAddress(6666));
// 4. 獲取選擇器
Selector selector = Selector.open();
// 4.1將通道註冊到選擇器上,指定接收“監聽通道”事件
server.register(selector, SelectionKey.OP_ACCEPT);
// 5. 輪訓地獲取選擇器上已“就緒”的事件--->只要select()>0,說明已就緒
while (selector.select() > 0) {
// 6. 獲取當前選擇器所有註冊的“選擇鍵”(已就緒的監聽事件)
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
// 7. 獲取已“就緒”的事件,(不同的事件做不同的事)
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
// 接收事件就緒
if (selectionKey.isAcceptable()) {
// 8. 獲取客戶端的連結
SocketChannel client = server.accept();
// 8.1 切換成非阻塞狀態
client.configureBlocking(false);
// 8.2 註冊到選擇器上-->拿到客戶端的連線為了讀取通道的資料(監聽讀就緒事件)
client.register(selector, SelectionKey.OP_READ);
} else if (selectionKey.isReadable()) { // 讀事件就緒
// 9. 獲取當前選擇器讀就緒狀態的通道
SocketChannel client = (SocketChannel) selectionKey.channel();
// 9.1讀取資料
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 9.2得到檔案通道,將客戶端傳遞過來的圖片寫到本地專案下(寫模式、沒有則建立)
FileChannel outChannel = FileChannel.open(Paths.get("2.png"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
while (client.read(buffer) > 0) {
// 在讀之前都要切換成讀模式
buffer.flip();
outChannel.write(buffer);
// 讀完切換成寫模式,能讓管道繼續讀取檔案的資料
buffer.clear();
}
}
// 10. 取消選擇鍵(已經處理過的事件,就應該取消掉了)
iterator.remove();
}
}
}
}
客戶端:
public class NoBlockClient {
public static void main(String[] args) throws IOException {
// 1. 獲取通道
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 6666));
// 1.1切換成非阻塞模式
socketChannel.configureBlocking(false);
// 1.2獲取選擇器
Selector selector = Selector.open();
// 1.3將通道註冊到選擇器中,獲取服務端返回的資料
socketChannel.register(selector, SelectionKey.OP_READ);
// 2. 傳送一張圖片給服務端吧
FileChannel fileChannel = FileChannel.open(Paths.get("X:\\Users\\ozc\\Desktop\\面試造火箭\\1.png"), StandardOpenOption.READ);
// 3.要使用NIO,有了Channel,就必然要有Buffer,Buffer是與資料打交道的呢
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 4.讀取本地檔案(圖片),傳送到伺服器
while (fileChannel.read(buffer) != -1) {
// 在讀之前都要切換成讀模式
buffer.flip();
socketChannel.write(buffer);
// 讀完切換成寫模式,能讓管道繼續讀取檔案的資料
buffer.clear();
}
// 5. 輪訓地獲取選擇器上已“就緒”的事件--->只要select()>0,說明已就緒
while (selector.select() > 0) {
// 6. 獲取當前選擇器所有註冊的“選擇鍵”(已就緒的監聽事件)
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
// 7. 獲取已“就緒”的事件,(不同的事件做不同的事)
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
// 8. 讀事件就緒
if (selectionKey.isReadable()) {
// 8.1得到對應的通道
SocketChannel channel = (SocketChannel) selectionKey.channel();
ByteBuffer responseBuffer = ByteBuffer.allocate(1024);
// 9. 知道服務端要返回響應的資料給客戶端,客戶端在這裡接收
int readBytes = channel.read(responseBuffer);
if (readBytes > 0) {
// 切換讀模式
responseBuffer.flip();
System.out.println(new String(responseBuffer.array(), 0, readBytes));
}
}
// 10. 取消選擇鍵(已經處理過的事件,就應該取消掉了)
iterator.remove();
}
}
}
}
文章以純面試的角度去講解,所以有很多的細節是未鋪墊的。
鑑於很多同學反饋沒看懂【對線面試官】系列,基礎相關的知識我確實寫過文章講解過啦,但有的同學就是不愛去翻。
為了讓大家有更好的體驗,我把基礎文章也找出來(重要的知識點我還整理過電子書,比如說像多執行緒、集合這種面試必考的早就已經轉成PDF格式啦)
我把這些上傳到網盤,你們有需要直接下載就好了。做到這份上了,不會還想白嫖吧?點贊和轉發又不用錢。
連結:https://pan.baidu.com/s/1pQTuKBYsHLsUR5ORRAnwFg 密碼:3wom
歡迎關注我的微信公眾號【Java3y】來聊聊Java面試