文章目录
2021SC@SDUSC
NIOServerCnxn继承了ServerCnxn抽象类,使用NIO来处理与客户端之间的通信。
源码分析
(1)属性
//日志
private static final Logger LOG = LoggerFactory.getLogger(NIOServerCnxn.class);
//基于NIO的ServerCnxn工厂
private final NIOServerCnxnFactory factory;
//面向流的连接套接字的可选择的通道
private final SocketChannel sock;
//Selector线程
private final SelectorThread selectorThread;
//表示可选择的通道在Selector中注册的标记
private final SelectionKey sk;
//是否初始化标志
private boolean initialized;
//分配四个字节缓冲区,以及赋值
private final ByteBuffer lenBuffer = ByteBuffer.allocate(4);
private ByteBuffer incomingBuffer = lenBuffer;
//创建缓冲队列
private final Queue<ByteBuffer> outgoingBuffers = new LinkedBlockingQueue<ByteBuffer>();
//会话超时
private int sessionTimeout;
//会话ID
private long sessionId;
(2)构造函数,在构造函数中会对Socket通道进行相应设置,如设置TCP连接无延迟、获取客户端的IP地址并将此信息进行记录,方便后续认证,最后设置SelectionKey感兴趣的操作类型为read。
public NIOServerCnxn(ZooKeeperServer zk, SocketChannel sock, SelectionKey sk, NIOServerCnxnFactory factory, SelectorThread selectorThread) throws IOException {
super(zk);
//设置socket通道
this.sock = sock;
this.sk = sk;
this.factory = factory;
this.selectorThread = selectorThread;
if (this.factory.login != null) {
this.zooKeeperSaslServer = new ZooKeeperSaslServer(factory.login);
}
sock.socket().setTcpNoDelay(true);
/* 设置linger为false,以便在socket关闭时不会阻塞 */
sock.socket().setSoLinger(false, -1);
//获取IP地址
InetAddress addr = ((InetSocketAddress) sock.socket().getRemoteSocketAddress()).getAddress();
//认证信息中添加IP地址
addAuthInfo(new Id("ip", addr.getHostAddress()));
//设置感兴趣的操作类型
this.sessionTimeout = factory.sessionlessCnxnTimeout;
}
(3)核心函数——doIO(),该函数主要是进行IO处理
void doIO(SelectionKey k) throws InterruptedException {
try {
if (!isSocketOpen