使用 nio-selector
。
引入自写的方法类。
下载 JAVA 文件
netty 包
1 2 3 4 5
| <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.86.Final</version> </dependency>
|
事件
accept
connect
read
write
事件发生后,要么处理,要么取消,不能置之不理。
代码
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| package com.redisc;
import lombok.extern.slf4j.Slf4j;
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.ArrayList; import java.util.Iterator; import java.util.List;
import static com.redisc.ByteBufferUtil.debugRead;
@Slf4j(topic = "c.Test") public class Run {
public static void main(String[] args) throws IOException { Selector selector = Selector.open(); ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.configureBlocking(false);
SelectionKey sscKey = ssc.register(selector, 0, null); sscKey.interestOps(SelectionKey.OP_ACCEPT); log.debug("register key:{}", sscKey);
ssc.bind(new InetSocketAddress(8090)); while (true) { selector.select(); Iterator<SelectionKey> iter = selector.selectedKeys().iterator(); while (iter.hasNext()) { SelectionKey key = iter.next(); log.debug("key:{}", key); ServerSocketChannel channel = (ServerSocketChannel) key.channel(); SocketChannel sc = channel.accept(); log.debug("{}", sc); }
} }
}
|
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13
| package com.redisc;
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.SocketChannel;
public class Client { public static void main(String[] args) throws IOException { SocketChannel sc = SocketChannel.open(); sc.connect(new InetSocketAddress("localhost", 8090)); System.out.println("waiting..."); } }
|
使用
开启服务端,并开启两个客户端。
输出
1 2 3 4 5
| 10:22:35.361 [main] DEBUG c.Test - register key:sun.nio.ch.SelectionKeyImpl@497470ed 10:22:38.740 [main] DEBUG c.Test - key:sun.nio.ch.SelectionKeyImpl@497470ed 10:22:38.744 [main] DEBUG c.Test - java.nio.channels.SocketChannel[connected local=/127.0.0.1:8090 remote=/127.0.0.1:59237] 10:22:41.689 [main] DEBUG c.Test - key:sun.nio.ch.SelectionKeyImpl@497470ed 10:22:41.689 [main] DEBUG c.Test - java.nio.channels.SocketChannel[connected local=/127.0.0.1:8090 remote=/127.0.0.1:59242]
|
假设不处理事件
如果,我们把 while
循环中的事件处理给注释掉。服务端代码的 46 - 48
1 2 3
| ServerSocketChannel channel = (ServerSocketChannel) key.channel(); SocketChannel sc = channel.accept(); log.debug("{}", sc);
|
开启服务端,开启一个客户端。
会进行无限循环。
1 2 3 4 5
| 10:25:30.210 [main] DEBUG c.Test - key:sun.nio.ch.SelectionKeyImpl@497470ed 10:25:30.210 [main] DEBUG c.Test - key:sun.nio.ch.SelectionKeyImpl@497470ed 10:25:30.210 [main] DEBUG c.Test - key:sun.nio.ch.SelectionKeyImpl@497470ed 10:25:30.210 [main] DEBUG c.Test - key:sun.nio.ch.SelectionKeyImpl@497470ed 10:25:30.210 [main] DEBUG c.Test - key:sun.nio.ch.SelectionKeyImpl@497470ed
|
这是因为,selector.select();
在事件未处理的时候不会阻塞。当有时间没有处理,会被重新添加,直到时间处理了。
事件取消
如果,就是不想处理事件,可以进行事件取消,将服务器 45 - 48
代码替换为
这样就不会进入无限循环了。