好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Netty客户端接入流程NioSocketChannel创建解析

前文传送门: Netty客户端处理接入事件handle创建

NioSocketChannel的创建

回到上一小节的read()方法

?

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

public void read() {

     //必须是NioEventLoop方法调用的, 不能通过外部线程调用

     assert eventLoop().inEventLoop();

     //服务端channel的config

     final ChannelConfig config = config();

     //服务端channel的pipeline

     final ChannelPipeline pipeline = pipeline();

     //处理服务端接入的速率

     final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();

     //设置配置

     allocHandle.reset(config);

     boolean closed = false ;

     Throwable exception = null ;

     try {

         try {

             do {

                 //创建jdk底层的channel

                 //readBuf用于临时承载读到链接

                 int localRead = doReadMessages(readBuf);

                 if (localRead == 0 ) {

                     break ;

                 }

                 if (localRead < 0 ) {

                     closed = true ;

                     break ;

                 }

                 //分配器将读到的链接进行计数

                 allocHandle.incMessagesRead(localRead);

                 //连接数是否超过最大值

             } while (allocHandle.continueReading());

         } catch (Throwable t) {

             exception = t;

         }

         int size = readBuf.size();

         //遍历每一条客户端连接

         for ( int i = 0 ; i < size; i ++) {

             readPending = false ;

             //传递事件, 将创建NioSokectChannel进行传递

             //最终会调用ServerBootstrap的内部类ServerBootstrapAcceptor的channelRead()方法

             pipeline.fireChannelRead(readBuf.get(i));

         }

         readBuf.clear();

         allocHandle.readComplete();

         pipeline.fireChannelReadComplete();

         //代码省略

     } finally {

         //代码省略

     }

}

我们继续剖析int localRead = doReadMessages(readBuf)这一部分逻辑

我们首先看readBuf

?

1

private final List<Object> readBuf = new ArrayList<Object>();

这里只是简单的定义了一个ArrayList, doReadMessages(readBuf)方法就是将读到的链接放在这个list中, 因为这里是NioServerSocketChannel所以这走到了NioServerSocketChannel的doReadMessage()方法

跟到doReadMessage()方法中:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

protected int doReadMessages(List<Object> buf) throws Exception {

     //根据当前jdk底层的serverSocketChannel拿到jdk底层channel

     SocketChannel ch = javaChannel().accept();

     try {

         if (ch != null ) {

             //封装成一个NioSokectChannel扔到buf中

             buf.add( new NioSocketChannel( this , ch));

             return 1 ;

         }

     } catch (Throwable t) {

         //代码省略

     }

     return 0 ;

}

jdk底层相关的内容

首先根据jdk的ServerSocketChannel拿到jdk的Channel, 熟悉Nio的小伙伴应该不会陌生

封装成一个NioSokectChannel扔到Readbuf中

这里的NioSocketChannel是对jdk底层的SocketChannel的包装, 我们看到其构造方法传入两个参数, this代表当前NioServerSocketChannel, ch代表jdk的SocketChannel

我们跟到NioSocketChannel的构造方法中:

?

1

2

3

4

public NioSocketChannel(Channel parent, SocketChannel socket) {

     super (parent, socket);

     config = new NioSocketChannelConfig( this , socket.socket());

}

这里看到调用了父类构造方法, 传入两个参数, parent代表创建自身channel的, NioServerSocketChannel, socket代表jdk底层的socketChannel

跟到父类构造方法中

?

1

2

3

protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) {

     super (parent, ch, SelectionKey.OP_READ);

}

其中SelectionKey.OP_READ代表其监听事件是读事件

继续跟父类的构造方法:

?

1

2

3

4

5

6

7

8

9

10

11

protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {

     super (parent);

     this .ch = ch;

     this .readInterestOp = readInterestOp;

     try {

         //设置为非阻塞

         ch.configureBlocking( false );

     } catch (IOException e) {

         //代码省略

     }

}

这里初始化了自身成员变量ch, 就是jdk底层的SocketChannel, 并初始化了自身的监听事件readInterestOp, 也就是读事件

ch.configureBlocking(false)这一步熟悉nio的小伙伴也不陌生, 就是将jdk的SocketChannel设置为非阻塞

我们继续跟到父类构造方法中:

?

1

2

3

4

5

6

protected AbstractChannel(Channel parent) {

     this .parent = parent;

     id = newId();

     unsafe = newUnsafe();

     pipeline = newChannelPipeline();

}

这里初始化parent, 也就是创建自身的NioServerSocketChannel, 并为自身创建了唯一id

初始化unsafe, 我们跟到newUnsafe()方法中

由于此方法是NioEventLoop调用的, 所以会走到其父类AbstractNioByteChannel的newUnsafe()

跟到newUnsafe()中:

?

1

2

3

protected AbstractNioUnsafe newUnsafe() {

     return new NioByteUnsafe();

}

这里创建了NioByteUnsafe对象, 所以NioSocketChannel对应的unsafe是NioByteUnsafe

继续往下跟, 我们看到其初始化了pipeline, 有关pipline的知识, 我们会在下一章节中讲到

回到NioSocketChannel中的构造方法:

?

1

2

3

4

public NioSocketChannel(Channel parent, SocketChannel socket) {

     super (parent, socket);

     config = new NioSocketChannelConfig( this , socket.socket());

}

同NioServerSocketChannel一样, 这里也初始化了一个Config属性, 传入两个参数, 当前NioSocketChannel自身和jdk的底层SocketChannel的socket对象

我们跟进其构造方法

?

1

2

3

private NioSocketChannelConfig(NioSocketChannel channel, Socket javaSocket) {

     super (channel, javaSocket);

}

同样, 这个类是NioSocketChannel的内部类

继续跟父类构造方法:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

public DefaultSocketChannelConfig(SocketChannel channel, Socket javaSocket) {

     super (channel);

     if (javaSocket == null ) {

         throw new NullPointerException( "javaSocket" );

     }

     //保存当前javaSocket

     this .javaSocket = javaSocket;

     //是否禁止Nagle算法

     if (PlatformDependent.canEnableTcpNoDelayByDefault()) {

         try {

             setTcpNoDelay( true );

         } catch (Exception e) {

         }

     }

}

这里保存了SocketChannel的socket对象, 并且默认的情况禁止了Nagle算法, 有关Nagle, 感兴趣的同学可以学习下相关知识

继续跟到父类构造方法中:

?

1

2

3

public DefaultChannelConfig(Channel channel) {

     this (channel, new AdaptiveRecvByteBufAllocator());

}

又跟到到了我们熟悉的部分了, 也就是说, 无论NioServerSocketChannel和NioSocketChannel, 最后都会初始化DefaultChannelConfig, 并创建可变ByteBuf分配器, 我们之前小节对此做过详细剖析这里不再赘述, 这部分忘记的内容可以阅读之前小节内容进行回顾

这个分配器什么时候真正分配字节缓冲的呢?我们会在之后的章节进行详细剖析

至此我们剖析完成了NioSocketChannel的初始化过程

以上就是Netty客户端接入流程NioSocketChannel创建源码解析的详细内容,更多关于Netty客户端接入流程NioSocketChannel的资料请关注其它相关文章!

原文链接:https://www.cnblogs.com/xiangnan6122/p/10204015.html

查看更多关于Netty客户端接入流程NioSocketChannel创建解析的详细内容...

  阅读:17次