日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

记一次JavaNIO重复读消费

發布時間:2024/9/19 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 记一次JavaNIO重复读消费 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在一次服務器端接收客戶端發送的消息時,服務器端一直觸發讀就緒事件,導致服務端代碼出現死循環,代碼如下

客戶端

public class Client1 {public static void main(String[] args) throws IOException, InterruptedException {SocketChannel socketChannel = SocketChannel.open();socketChannel.configureBlocking(false);InetSocketAddress localhost = new InetSocketAddress("localhost", 8888);socketChannel.connect(localhost);while (!socketChannel.isConnected()) {socketChannel.finishConnect();}socketChannel.write(ByteBuffer.wrap("客戶端數據".getBytes()));} }

服務端

public class Server1 {public static void main(String[] args) throws IOException {ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();InetSocketAddress inetSocketAddress = new InetSocketAddress(8888);serverSocketChannel.bind(inetSocketAddress);serverSocketChannel.configureBlocking(false);Selector selector = Selector.open();serverSocketChannel.register(selector, 16);while (true) {int select = selector.select();System.out.println("當前有" + select + "個操作就緒");Set<SelectionKey> keys = selector.selectedKeys();Iterator<SelectionKey> iterator = keys.iterator();while (iterator.hasNext()) {SelectionKey next = iterator.next();if (next.isAcceptable()) {System.out.println("accept就緒++++++++++++++");ServerSocketChannel server = (ServerSocketChannel) next.channel();SocketChannel socketChannel = server.accept();socketChannel.configureBlocking(false);socketChannel.register(selector, SelectionKey.OP_READ);} else if (next.isReadable()) {System.out.println("讀就緒+++++++++++++++++");ByteBuffer allocate = ByteBuffer.allocate(10240000);StringBuffer stringBuffer = new StringBuffer();SocketChannel channel = (SocketChannel) next.channel();int read = channel.read(allocate);while (read > 0) {allocate.flip();stringBuffer.append(new String(allocate.array(), 0, read));allocate.clear();read = channel.read(allocate);}System.out.println(stringBuffer);}}iterator.remove();}} }

執行結果

最后在一個帖子里看到了答案https://segmentfault.com/q/1010000019694209

原因

  • 如果客戶端的socket斷開連接后,會一直向服務端發送一個讀就緒,即channel.read(allocate)=-1,這個時候服務端應該斷開這個連接,或者至少注銷掉OP_READ。

驗證

  • 在客戶端的代碼最后加一個線程睡眠,Thread.sleep(1000000L);
    可以看到,在客戶端代碼執行結束之前,服務端不會收到這個讀就緒事件

解決

服務器端代碼加上判斷

public class Server1 {public static void main(String[] args) throws IOException {ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();InetSocketAddress inetSocketAddress = new InetSocketAddress(8888);serverSocketChannel.bind(inetSocketAddress);serverSocketChannel.configureBlocking(false);Selector selector = Selector.open();serverSocketChannel.register(selector, 16);while (true) {int select = selector.select();System.out.println("當前有" + select + "個操作就緒");Set<SelectionKey> keys = selector.selectedKeys();Iterator<SelectionKey> iterator = keys.iterator();while (iterator.hasNext()) {SelectionKey next = iterator.next();if (next.isAcceptable()) {System.out.println("accept就緒++++++++++++++");ServerSocketChannel server = (ServerSocketChannel) next.channel();SocketChannel socketChannel = server.accept();socketChannel.configureBlocking(false);socketChannel.register(selector, SelectionKey.OP_READ);} else if (next.isReadable()) {System.out.println("讀就緒+++++++++++++++++");ByteBuffer allocate = ByteBuffer.allocate(10240000);StringBuffer stringBuffer = new StringBuffer();SocketChannel channel = (SocketChannel) next.channel();int read = channel.read(allocate);while (read > 0) {allocate.flip();stringBuffer.append(new String(allocate.array(), 0, read));allocate.clear();read = channel.read(allocate);}System.out.println(stringBuffer);// socket已經斷開if (read == -1) {//增加注銷操作// int readyOps = next.readyOps();//&~xx 代表取消事件,取反 按位與// next.interestOps(next.interestOps() & ~readyOps);// 或者斷開服務端的這個socketchannel.close();}}}iterator.remove();}} }

總結

以上是生活随笔為你收集整理的记一次JavaNIO重复读消费的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。