记一次JavaNIO重复读消费
生活随笔
收集整理的這篇文章主要介紹了
记一次JavaNIO重复读消费
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
在一次服務(wù)器端接收客戶端發(fā)送的消息時(shí),服務(wù)器端一直觸發(fā)讀就緒事件,導(dǎo)致服務(wù)端代碼出現(xiàn)死循環(huán),代碼如下
客戶端
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("客戶端數(shù)據(jù)".getBytes()));} }服務(wù)端
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("當(dāng)前有" + select + "個(gè)操作就緒");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();}} }執(zhí)行結(jié)果
最后在一個(gè)帖子里看到了答案https://segmentfault.com/q/1010000019694209
原因
- 如果客戶端的socket斷開(kāi)連接后,會(huì)一直向服務(wù)端發(fā)送一個(gè)讀就緒,即channel.read(allocate)=-1,這個(gè)時(shí)候服務(wù)端應(yīng)該斷開(kāi)這個(gè)連接,或者至少注銷掉OP_READ。
驗(yàn)證
- 在客戶端的代碼最后加一個(gè)線程睡眠,Thread.sleep(1000000L);
可以看到,在客戶端代碼執(zhí)行結(jié)束之前,服務(wù)端不會(huì)收到這個(gè)讀就緒事件
解決
服務(wù)器端代碼加上判斷
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("當(dāng)前有" + select + "個(gè)操作就緒");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已經(jīng)斷開(kāi)if (read == -1) {//增加注銷操作// int readyOps = next.readyOps();//&~xx 代表取消事件,取反 按位與// next.interestOps(next.interestOps() & ~readyOps);// 或者斷開(kāi)服務(wù)端的這個(gè)socketchannel.close();}}}iterator.remove();}} }總結(jié)
以上是生活随笔為你收集整理的记一次JavaNIO重复读消费的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 苹果iphone手机开不了机了无反应怎么
- 下一篇: 记一次Debian11安装