selector.select()
会阻塞等待4中事件发生
/**
* Operation-set bit for read operations.
*
* <p> Suppose that a selection key's interest set contains
* <tt>OP_READ</tt> at the start of a <a
* href="Selector.html#selop">selection operation</a>. If the selector
* detects that the corresponding channel is ready for reading, has reached
* end-of-stream, has been remotely shut down for further reading, or has
* an error pending, then it will add <tt>OP_READ</tt> to the key's
* ready-operation set and add the key to its selected-key set. </p>
*/
public static final int OP_READ = 1 << 0;
/**
* Operation-set bit for write operations.
*
* <p> Suppose that a selection key's interest set contains
* <tt>OP_WRITE</tt> at the start of a <a
* href="Selector.html#selop">selection operation</a>. If the selector
* detects that the corresponding channel is ready for writing, has been
* remotely shut down for further writing, or has an error pending, then it
* will add <tt>OP_WRITE</tt> to the key's ready set and add the key to its
* selected-key set. </p>
*/
public static final int OP_WRITE = 1 << 2;
/**
* Operation-set bit for socket-connect operations.
*
* <p> Suppose that a selection key's interest set contains
* <tt>OP_CONNECT</tt> at the start of a <a
* href="Selector.html#selop">selection operation</a>. If the selector
* detects that the corresponding socket channel is ready to complete its
* connection sequence, or has an error pending, then it will add
* <tt>OP_CONNECT</tt> to the key's ready set and add the key to its
* selected-key set. </p>
*/
public static final int OP_CONNECT = 1 << 3;
/**
* Operation-set bit for socket-accept operations.
*
* <p> Suppose that a selection key's interest set contains
* <tt>OP_ACCEPT</tt> at the start of a <a
* href="Selector.html#selop">selection operation</a>. If the selector
* detects that the corresponding server-socket channel is ready to accept
* another connection, or has an error pending, then it will add
* <tt>OP_ACCEPT</tt> to the key's ready set and add the key to its
* selected-key set. </p>
*/
public static final int OP_ACCEPT = 1 << 4;
读事件
写事件
connect事件
accept事件
写事件是比较特殊的一种,因为channel一般情况下都是可写的,所以我们如果注册写事件,然后select()方法看到channel可写,就不会阻塞,最后走到key.isWritable判断为true,然后一直循环
while(true){
selector.select()
val iterator = selector.selectedKeys().iterator()
while (iterator.hasNext()) {
val key = iterator.next()
iterator.remove()
if (key.isWritable){
}
}
}
netty中的用法是这样的
@Override
protected void doWrite(ChannelOutboundBuffer in) throws Exception {
//获取循环写N次,设置写N次的原因是当循环发送,线程就会不断尝试写操作,此时线程就无法处理其他请求,如果网络状况不好或者对方接收太慢,可能会导致线程假死
int writeSpinCount = config().getWriteSpinCount();
do {
//从上次位置开始
Object msg = in.current();
if (msg == null) {
// 写完了,清理write操作位
clearOpWrite();
return;
}
//doWriteInternal中 会记录发送了多少数据,这样当IO复用器再次轮询就可以继续发送剩余的数据
writeSpinCount -= doWriteInternal(in, msg);
} while (writeSpinCount > 0);
//写N次之后没写完,设置write操作位,这样线程可以处理其他事件
incompleteWrite(writeSpinCount < 0);
}
protected final void incompleteWrite(boolean setOpWrite) {
if (setOpWrite) {
//设置write标志位,这样IO复用器就会不断轮询对应channel 来处理未发送的半包
setOpWrite();
} else {
//如果不设置标志位,则新建一个任务放入线程池
clearOpWrite();
eventLoop().execute(flushTask);
}
}