需要注意的时候上面并没有设置当前channel监听的事件,真正设置监听的事件类型是在beginRead方法里面,在当前channel被激活的时候会调用beginRead方法
// io.netty.channel.nio.AbstractNioChannel#doBeginRead protected void doBeginRead() throws Exception { // Channel.read() or ChannelHandlerContext.read() was called final SelectionKey selectionKey = this.selectionKey; if (!selectionKey.isValid()) { return; } readPending = true; final int interestOps = selectionKey.interestOps(); if ((interestOps & readInterestOp) == 0) { // readInterestOp是16,在NioServerSocketChannel构造方法里面指定了这个channel需要监听accept事件 // 这里才是真正设置socket监听事件的地方 // 下面这个方法最后会调用到sun.nio.ch.EPollArrayWrapper#setInterest selectionKey.interestOps(interestOps | readInterestOp); } } // sun.nio.ch.EPollArrayWrapper#setInterest void setInterest(int fd, int mask) { synchronized (updateLock) { // record the file descriptor and events int oldCapacity = updateDescriptors.length; if (updateCount == oldCapacity) { int newCapacity = oldCapacity + INITIAL_PENDING_UPDATE_SIZE; int[] newDescriptors = new int[newCapacity]; System.arraycopy(updateDescriptors, 0, newDescriptors, 0, oldCapacity); updateDescriptors = newDescriptors; } updateDescriptors[updateCount++] = fd; // events are stored as bytes for efficiency reasons byte b = (byte)mask; assert (b == mask) && (b != KILLED); // 上面已经说过这个方法了,把当前socket对应的文件描述符监听的事件设置为b setUpdateEvents(fd, b, false); } }到这里一个serverSocketChannel注册成功了,而且也设置了关注的事件,接下来看看完成ip:port的绑定
public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException { synchronized (lock) { // 省略中间代码... // 调用native方法的bind,最后调用linux的bind方法 Net.bind(fd, isa.getAddress(), isa.getPort()); // 最后调用listen方法完成监听serverSocket的文件描述符 Net.listen(fd, backlog < 1 ? 50 : backlog); synchronized (stateLock) { localAddress = Net.localAddress(fd); } } return this; } 总结server在bind的过程中主要初始化了NioServerSocketChannel,并将channel注册到selector,添加了channel需要监听的事件,接下来该socketChannel就可以监听端口接受来自客户端的请求了。