當前位置:
首頁 >
记一次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重复读消费的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果iphone手机开不了机了无反应怎么
- 下一篇: 排序算法(Java实现)