ネッティー新しい接続アクセス手順
新しいリンクの1検出...> 2 NioSocketChannel-> 3スレッド割り当て及び登録を作成selector-登録>図4は、セレクタにイベントを読み取ります
新しい接続の検出
ステップ
- processSelectedKey(キー、チャンネル)入口
- NioMessageUnsafe.read()
- doReadMessages()whileループ
- javaChannel()。(受け入れます)
- doReadMessages()whileループ
- NioMessageUnsafe.read()
分析
- processSelectedKey(キー、チャンネル)入口
private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();
try {
int readyOps = k.readyOps();
// 省略代码...
if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
// 调用与ServerSocketChannel绑定的
unsafe.read();
}
} catch (CancelledKeyException ignored) {
unsafe.close(unsafe.voidPromise());
}
}
复制代码
doReadMessages()
@Override
protected int doReadMessages(List<Object> buf) throws Exception {
// 接收客户端连接
SocketChannel ch = SocketUtils.accept(javaChannel());
try {
if (ch != null) {
// netty创建自己的客户端channel
buf.add(new NioSocketChannel(this, ch));
return 1;
}
} catch (Throwable t) {
//省略代码...
}
return 0;
}
复制代码
NioSocketChannelを作成します
ステップ
- 新しいNioSocketChannel(親、CH)入口
- AbstractNioByteChannel(P、CH、OP_READ)
- configureBlocking(偽)&OPを保存
- IDを作成し、危険な、パイプライン
- 新しいNioSocketChannelConfig()
- setTcpNoDelay(真)
- AbstractNioByteChannel(P、CH、OP_READ)
分析
- 新しいNioSocketChannel(親、CH)入口
public NioSocketChannel(Channel parent, SocketChannel socket) {
super(parent, socket);
// 创建channel对应的config
config = new NioSocketChannelConfig(this, socket.socket());
}
protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) {
// 指定channel关注读事件
super(parent, ch, SelectionKey.OP_READ);
}
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
super(parent);
this.ch = ch;
this.readInterestOp = readInterestOp;
try {
ch.configureBlocking(false);
} catch (IOException e) {
//省略代码..
}
}
复制代码
- 我々はこの時点でsetTcpNoDelay(真)で述べたと同様のプロセスを作成するために、他のサーバーチャネル、
public SocketChannelConfig setTcpNoDelay(boolean tcpNoDelay) {
try {
// 如果不是安卓就true
javaSocket.setTcpNoDelay(tcpNoDelay);
} catch (SocketException e) {
throw new ChannelException(e);
}
return this;
}
当开启nagle算法时,客户端首先发送大小为1字节的第一个分组,随后其它分组到达发送缓冲区,由于上一个分组的应答还没有收到,所以TCP会先缓存新来的这4个小分组,并将其重新分组,组成一个大小为8(2+3+1+2)字节的”较大的”小分组。当第一个小分组的应答收到后,客户端将这个8字节的分组发送。总共发送的报文段(分组)个数为2。当传输数据存在大量交互数据时,nagle算法可以有效减少网络中的报文段个数
/**
* Disable Nagle's algorithm for this connection. Written data
* to the network is not buffered pending acknowledgement of
* previously written data.
*/
@Native public final static int TCP_NODELAY = 0x0001;
复制代码
網状の分類チャンネル
ステップ
- NioServerSocketChannel
- NioSocketChannel
分析
- 簡略化されたクラス図
処理の前に作成したチャンネルは、クライアントとサーバーのチャネルは、パブリックメンバ変数を持っています。彼らのクラスの継承関係が示されています:
新しい接続NioEventLoop配分と登録セレクタ
ステップ
> ServerBootstrapAcceptor - - >テールパイプラインのサービス側はチャンネルヘッドを構成します
- ServerBootstrapAcceptor
- childHandlerを追加
- オプションとATTRSの設定
- セレクタNioEventLoppを選択して登録するセレクタ
分析
- サービス側チャネルが作成時点でパイプラインのServerBootstrapAcceptorを追加します。
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) throws Exception {
final ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
复制代码
- 選択はそのうち1が1とチャンネル登録までのイベントループになるための究極のものを作成するためのServerBootstrapAcceptorプロセスは、childGroupを初期化することです
- 接続イベント用の上記doReadMessagesが実際に読んNioSocketChannelです
int size = readBuf.size();
for (int i = 0; i < size; i ++) {
readPending = false;
// 关键点在这,这句话的意思是 serverSocketChannel.pipeline().fireChannelRead(nioSocketChannel)
pipeline.fireChannelRead(readBuf.get(i));
}
// serverAcceptor的channelRead方法
public void channelRead(ChannelHandlerContext ctx, Object msg) {
// 省略代码 ...
// child 也就是我们上面说的 nioSocketChannel
final Channel child = (Channel) msg;
// 那么这句话的意思就是 把nioSocketChannel注册到EventLoop的其中一个的selector上
childGroup.register(child).addListener(...);
}
复制代码
- NioSocketChannel登録プロセス
public ChannelFuture register(Channel channel) {
// next()其实就是我们之前在EventLoop中提到的EventLoop选择的问题,这块是个轮询详情请看EventLoop那篇文章
return next().register(channel);
}
public ChannelFuture register(final ChannelPromise promise) {
ObjectUtil.checkNotNull(promise, "promise");
// 这块其实是调用与客户端Channel所对应的unsafe
promise.channel().unsafe().register(this, promise);
return promise;
}
// 一直跟到最后的register.
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
// 这块还没有监听具体的事件
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
return;
} catch (CancelledKeyException e) {
...
}
}
}
复制代码
- interestOpsセレクタのセット
// readInterestOp上边设置的是OP_READ,也就是监听读事件
protected void doBeginRead() throws Exception {
...
final int interestOps = selectionKey.interestOps();
if ((interestOps & readInterestOp) == 0) {
selectionKey.interestOps(interestOps | readInterestOp);
}
}
复制代码