selector
channel的四种事件
ServerSocketChannel有效事件为accept
socketChannel有效事件为connect、read、write
accept事件在ServerSocketChannel在接收到新的连接时触发.
read事件在socketChannel有可读信息时触发
write事件在socketChannel有可写信息时触发
connect事件在socketChannel连接建立成功时触发
accept事件
ServerSocketChannel 处理事件
server
package com.hello.netty;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.*;
import java.util.Iterator;
@Slf4j
public class Server {
public static void main(String[] args) throws IOException {
// 1. 创建 selector 管理多个channel
Selector selector = Selector.open();
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
// 2. 建立 selector 和 channel 的联系(channel注册到selector)
// SelectionKey 中包含了 selector 和 注册的 channel的信息.
SelectionKey sscKey = ssc.register(selector, 0, null);
// sscKey 只关注 accept事件
sscKey.interestOps(SelectionKey.OP_ACCEPT);
log.debug("register key: {}",sscKey);
ssc.bind(new InetSocketAddress(8080));
while(true){
// 3. select方法,没有事件发生时,线程阻塞,有事件发生时继续运行.
selector.select();
// 4. 处理事件
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while(iterator.hasNext()){
SelectionKey key = iterator.next();
log.debug("key: {}",key);
ServerSocketChannel channel = (ServerSocketChannel)key.channel();
SocketChannel sc = channel.accept();
log.debug("SocketChannel: {}",sc);
}
}
}
}
-
Selector selector = Selector.open();
创建了selector 对象【selector】 -
ServerSocketChannel ssc = ServerSocketChannel.open();
创建了ServerSocketChannel 对象【channel】 -
SelectionKey sscKey = ssc.register(selector, 0, null);
将channel注册到selector上,返回值为SelectionKey,包含了该selector信息和注册上来的channel信息。selector中有个SelectionKey的集合属性,包含了注册到该selector的所有channel信息。
selector.select();
是阻塞方法,如果注册到selector的所有channel都没有新事件发生,则线程处于阻塞状态。一旦存在有channel有新的事件发生,则继续向下执行。selector.selectedKeys()
返回一个set集合,是所有有新事件发生的channel集合。channel.accept();
处理ServerSocketChannel的事件。
client
package com.hello.netty;
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",8080));
System.out.println("waiting...");
}
}
说明
先启动server,然后再启动两个client
- SelectionKey地址一样
两个SelectionKey的地址sun.nio.ch.SelectionKeyImpl@2b71fc7e
一样,因为两个连接都建立在同一个serverSocketChannel上。
- SocketChannel地址不同
通过ServerSocketChannel#accept方法获取socketChannel,两个socketChannel的地址是不同的,是两个不同的socketChannel。
09:53:06.032 [main] DEBUG com.hello.netty.Server - register key: sun.nio.ch.SelectionKeyImpl@2b71fc7e
09:53:09.318 [main] DEBUG com.hello.netty.Server - key: sun.nio.ch.SelectionKeyImpl@2b71fc7e
09:53:09.318 [main] DEBUG com.hello.netty.Server - SocketChannel: java.nio.channels.SocketChannel[connected local=/127.0.0.1:8080 remote=/127.0.0.1:50530]
09:53:13.191 [main] DEBUG com.hello.netty.Server - key: sun.nio.ch.SelectionKeyImpl@2b71fc7e
09:53:13.191 [main] DEBUG com.hello.netty.Server - SocketChannel: java.nio.channels.SocketChannel[connected local=/127.0.0.1:8080 remote=/127.0.0.1:50536]