00:00
Net接收请求过程源码剖析。源码剖析的目的,服务器启动后肯定是要接客户端请求,并返回客户端想要信息的,下面呢源码分析net启动之后是如何接受客户端请求的,也就是说大家有没有发现我们在前边呢已经讲到这个位置了,就是哪一块。同学们看回到。回到我们na的。Net的模型。我们来说一下待会儿要分析的是哪一块代码。我们是不是。刚才已经分析出来了,我们的服务器端,服务器端它已经可以启动。那么现在是不是我们有必要去分析一下这个过程?就是。当我们。Boss group在这里处理,就是它连接,呃,他在这个这个地方进行一个except的时候,如果有一个客户端来连接了,就这边啊,这边一个客户端来连接了,我们是怎么在这个地方就是process selected k在这个方法里边去能够。
01:13
跟他建立一个呃连接,或者是建立一个通道China,然后呢,把这个China注册到我们的这个worker group上面去,我们就来分析这个过程,能理解吧。就说别人肯定会问你嘛,很多面试官他会问你,诶请问。就是当我们boss group跟。端有一个连接事件后,怎么把它这一个产生的。注册到我们worker group上面去。我们要从源码的级别来进行一个分析好了,那现在呢,把要分析的事情说清楚了,过后我们就来进行详细的源码剖析,回到我们的这个位置。好,首先呢,我们用的代码还是用。
02:03
IO ni自,呃,就ni自自自己提供的这么一个代码,我们来用一下。就还用前面写的这段代码吧。这儿。是不是有个事有个事,Echo server,还有一个e client,就用这个程序,咱们不去写新的东西了,直接看这里。我们来说明一下,之前从之前服务器启动的源码中我们得知,服务器最终呢,它会注册一个事件等待客户端的连接。我们也知道。N IO server呢?注,将自己注册到一个boss单利线程池,因为我们刚才起的。这个boss group它就是一个线程,也就是说现在是一个lo了,大家知道在这个event group里面呢,它会执行三件事情,一个是select。
03:00
对,然后是process。Process,我们的什么呀,这个case case对不对,就这个方法。Process select case,然后呢,还有一个就是我们的。Task。关于event的loop这个逻辑实际上我们在前面已经说过,说过一说过一些了,那这里呢,我们再来做一个简单回顾,在的loop里面,其实就是一个是等待RO的事件,一个是处理NR事件,一个是处理消息队列的任务,现在呢,我们就来分析。他在等待的时候,就是分析这这个过程。分析这个就他怎么知道这个事件是一个except事件呢。然后拿到这个APP件,怎么又把得到的China注册到他的worker group上面呢?好,我们来分析一下,首先呢,这里面我们要先找到这个process。我们先把这个方法找到,好吧,这个方法呢,我们来定一下位。
04:03
同学们,我们先来定一下这位这个方法。好的。咦,这个为什么没找到啊?李小卫。好,已经找到了,就这里。是吧,是不是就这个方法呀。就这个方法。那现在呢,我们看看能否进到这个位置去。看是不是这个地方哈。我们找到合适的位置。怎么怎么只有只有这一个地方吗。好,先进去看看是不是这个位置。看一下。嗯,好像不是这个位置,不是这个位置。不是柜子。好不是我再我再还重新在这找一下。那打开我们这个文档啊,不是这个位置,我得把我们这准备好的文档先打开。
05:02
打开这个。Net请求过程源码剖析,因为我这已经把文档准备好了。应该是找到process select。这个这这个代码。OK。往这看。好,在这儿我们先进去。其实大家可以看到这段代码呢,他也是在我们的process select k这个地方啊,这个现在。因为太多了,读起来特别绕口。Process selected key。然后呢,这个地方是我们的关键,就这个地方是我们的关键,对吧。这个地方呢,我下个断点就是644行下个断点。我要下个断点,我待会要看这个ready OPS到底是多少,大家还记不记得,如果是一个accept事件。如果是一个XX页呢,这个地方应该等于16,所以说我下面继续来走。我我把断点先先下在这里,下这里呢,我们用浏览器来发出一个请求。
06:04
这个浏览器不是向我们net服务器发个请求,我就可以来进行下步的bug,来吧,同学们。那现在呢,我启动服务器端。用debug的方式启动我们的服务器端。Debug。OK。好,现在呢,已然启动,我们打开浏览器。因为目前它监听端口是8007,我回撤。当我一回车断点呢,就应该下到这里来,同学们看,Readys就是16,同学们还记不记得16到底是什么事件,来看一下。Selection。走起来。同学们往下看。我们说ready呢,它其实是一。Right呢,是一乘以二,再乘以二就是。是。八而我们accept它其实就是16,那从这边可以看出来呢,的确现在ready OPS就是16,那下面我们执行一步,它会进入到unsafe ready,同学们看这个unsafe它是一个什么样的对象呢?来看一下。
07:13
从端点我们可以看到是16,是个X件,说明浏览器的请求怎么样过来了,能理解我的意思吧?那么onaf是boss线程,线程中的这一个类的就是这个对象类型是这个类型,那我们来定一下位,看看是不是这样子。同学们看uniefe,其实OBS的一个内部类的对象就是message on。也就是大家知道这个这这个他要进行一个什么,他要进行一个read操作,那我们看read是干什么的,往下走。我们来看read的方法,我们追进去。OK啊,现在我们进入到read的方法了,这个read的方法呢,它先下了个断言。这个断言是干什么呀,他判断他判断你这个线程,大家看可以看到这个断言的作用是干嘛呢。
08:07
检查的路谱线程是不是当前线程下了断言?那么紧接着它会执行一个do,叫做do message do read message这个方法,并传入一个read buffer变量,这个变量是一个list,那接着继续往下走。那就往下走哈,同学们看这里面很关键的一个动作,他在这里是不是已已经拿到了,拿到了我们这个pipeline。看到没有,拍烂就是管道,它已经得到了,紧接着继续往下走。继续往下走。Okay。好,包括我们的。China的config他也已经拿到了,再下一个断言,接着继续走。好,接着走。走进来,好同学们可以看到他现在do进入到do read message。那么这个read buffer是个什么呢?其实大家可以看到它是个list。现在S等于零,说明目前是空的。
09:02
那这个do read message,他要做一件什么事情呢?朋友们看到你。嗯呃,待会儿呢,我们会debug这个读message啊,同学们待会儿会。读这个message,我们现在这样子吧,先debug进去,再回到这边来执行下面的这个叫做fire China read,因为下面呢还有方法。是不是它下面还有一个fair China read这个方法呢?我们先待会再说,我们先来进到这个do read message,看看这里面是做了什么事情。大家看,To read message是读取boss线程中的IO server接收到请求,并把这些请求放入到容器,那现在我们进行第bug进去,各位朋友。OK,好,各位朋友,现在呢,我们已经进入到do read message。OK,那这个do read message,他做什么事情呢?请看往下看啊,往下看这个do read message。我们再看同时看它通过这个工具类,就是这个叫做socket u这个工具类。
10:06
呃,调用。这个工呃,就是说这个工具类通过IO server socket channel内部封装的一个叫server socket channel的accept方法,就它。OK。这个方法是NIO的一个做法,标准的一个做法,它会返回什么呢?就是返回我们真正要的东西,Short China,诶,往下走一步。诶,大家看是不是到这一步,到这一步其实我们就已经拿到了什么呀,So China。是不是so China这个时间他已经已然拿到了,只是现在还没有进行一个包装,它是socket channel,它实际实际上这个CH的类型呢,可以看到是。是一个soed China implement,那接着就往下走,往下走,各位朋友看到目前C不等于空看这里来了。是不是他把当前这一个CH,就是你拿到这个socket,把它六层呃,包装成了一个n IO socket,诶各位同学,这是不是就是我们所说的一个客户端。
11:15
跟我们服务器端进行连接,这个连接就被我们包装成了一个n IO so channel,并且加入到这个buffer里面去了,这个buffer是不是一个list呀?OK,然后这个时候他就完成他任务,返回一个一。继续往下玩。回来了。OK,那也就是说这个方法他做了什么事情呢?他获取了一个jdk socketer,然后使用n IO socket channeler进行一个封装,最后加入到容器,那么这样这个容器buffer里面就有了n IO socket channeler。刚才是不是我们已经把这个走了,如果说同学们有兴趣去追一下这个NL soet China,那么自己去看一下就行了,我这就不追了,也就是说大家至少要明白这个do read message呢,他拿到了我们这个so,就是JDK的一个,呃,So,他我这不说了吗?拿到一个JJDK的socket channel,然后把它封装成一个n IO socket并返回到返回,返回的时候呢,先把它加入到这个buffer里面去了。
12:18
OK,那接着我们继续往下分析,继续往下分析,同学们看这里。那么继续执行的话呢,我们就要去看这个pipeline fire。China read这个方法做了什么事情,大家有没有发现他其实是把什么东西啊,他从这个就是刚才返回的那个集合里面去得到你的那个n IO China。给他传到这个fire China read这个方法里面去,好,那现在我直接在这里定位。是不是这下个断点啊,我直接把断点放这来。同学们看这个read的,嗯,同学们看啊,这个时候这个reader buffer里面,这个reader buffer里面大家看它其实是个例子里面呢,已经有一个什么玩意了,N nio so China,其实这个就是我们客户端。
13:06
跟我们服务器端建立的China。那拿到这个China干什么事情呢?那我们就要来分析fire short China read,它要做什么事情来接着往下去分析我们的这个fair channel read的方法。我走。来,我们现在呢,回到read方法,继续分析这个fire。Read的方法。那这个方法呢?呃,这个方法我们看看需不需要追进去啊。China readid方法。China read方法,呃,我们就说一下它的功功能就行了,因为这里面代码东西太多啊,我先把它的要做的事情给给大家说清楚。前面我们已然分析了to read message,它的方法作用是通过server socket的accept方法得到TCB连接,然后将其封装成NIO双center,没问题吧?最后加入的容器在RA的方法里面呢?就在刚才那个方法里面,在这个方法里面它会循环调用socket server socket pan里面的fire。
14:13
Fire channel read方法开始执行管道中的handler的这一个channel read方法。也就是说这个方法里边,我们可以往里面注一下。最近去啊。追进去。好,追到这里面去了,这还得追这这个这个不是一一下就追到的。往对面追。好。你看这个地方它是循环的啦。循环的话。嗯,还得还得往这里面追哈,还得往这里面追。好,我们再往里面追一下。好,同学们,我们终于追到了,大家有没有发现?他在这里面做了一件什么事情呢?他是不是开始调用这个handleler,当然他先取得这个handleler,把转成了China inbound handleler,因为你现在数据是属于入账的。
15:07
然后调用了这个的方法是不是好的,那这个时候这个message呢,他也给你返回来了这个message。他这个message是不是这样子的,其实就是,呃,对方的一个是本地的一个地址是8007,另另外一个就是远程过来的,它的端口是61497,对不对,是这意思吧,同学们,OK,下面信息很多了,那现在我们回到这边来继续看这个方法就是。Read的这个方法,经过多次的debug,我们可以看到它会反复执行这个handler handler channel read的方法,为什么呢?就是因为这个目前我们这个拍烂。就是目前我们这个管道里面,其实它的handler已经有四个了,哪四个呢?来看一下,第一个是hide一个,第二个是logging handler一个,还有个是server boot,呃,Server boot strip accept,还有一个ta。
16:05
那我们现在呢,来看看是不是目前在他这个管道里面有四个handle呢,我们来看一下,那现在我得。我得找到。这个地方啊,我们来看看,那只有从这找了。不知道。好,我们找一下这个pipeline。这个排烂看第一个,它的第hi的第一个,大家翻到是是不是就是hide context,这是一个吧,接着往下注意。是不是它的下一个。它的下一个又是一个contact,这个context里面就应该有个handle,就是logging handler就是我们第二个,也就说这是大家可以这样理解,这个地方是我们的第一个。Context。OK,那么这个是我们的第二一个里面包含的handler,接着继续往下,下一个是不是就是还有一个刚才老师所说的serve boot strip accept,其实这个地方是关键,因为它是做accept的处理的。
17:04
就是你有你有这一个什么呀,请求事件他在这处理,那下一个呢,还有一个就是tell context。开开,这是他最后这一个我们所说的contact,那现在我现在比较关注的是哪一个呢?同学们,我们重点要看一下server boot strip。第八个过后呢,我们会看到断点会进入到这一个server boot strip里面来,它这里面有一个reader,这里面最关键的,同学们,这里面最关键,为什么这面最关键呢?因为他做了一个非常重要的动作,就在这里。大家看这段话,能看懂我在干什么事情吗?各位朋友就说他在这个地方呢,他会做这样一件事情,他在这地方会拿到。拿到你当前的这个这个charter group,我告诉大家这个charter group就是我们worker。
18:00
那个就是worker group,然后register注册把你这个child,这个child是不是就是个管道啊,同学们看。是不是就是你当前这个管道,把这个管道注册到。我们这个worker形成词。但是他这底层呢,他肯定会选一个你这个worker的某一个,呃,就NIO的loop。并且增加一个监听器,这个监听器呢,我们以前是用过的,如果成,如果不成功,它就会关闭啊,如果成功的话呢,他也没有做处理,看到没有,这是监听器。没问题吧,好,那这样子明白这个道理过后呢,我们就来看一下是不是会到这个位置来,好吧,会会不会到这个位置来,那现在呢,我我这个地方就调一下吧,我看看能掉几次,这次我干脆这次我们稍微快一点,我们就直接。追到这边去,这应该是第一次吧。返回。好,这样子我们快速一点,把前面断点挂掉,我们直接在这下个断点好吧,因为这追追追来追去的容容易追乱,我就直接在下个断点给大家看一下。
19:10
好朋友们。这个时候可能我要我要我要放几次断点哈来。找一个吧,同学们。来,走起来。好,我把重点下在这里。我把断点直接下这好吧,这样就会看起来比较快一点。好,这是下个专题,然后呢,我们直接把。待会跑出,哎,各位同学是不是来这了?是不是来这了,来到来到这里过后呢,同学们看,首先我们看这个char char group是什么玩意儿,挖走。对不看char group是不是就是n IO event,而且编号是1763,这个1763其实就是我们worker group,为什么能这么说呢?来看一下。是不是老师说的对不对,看这里,你看这里面是不是有个char group,它就是1763。看到没有,这边是不是也是要求的呢。
20:00
实际上就是我们的worker group register,不说了,这个就是你当前拿到的这个通道。是不是这个通道啊,8807和61497的一个通道,然后注册进去。OK啊,然后同时增加监听器,所以说到这里就是我们所谓的把你得到的一个China注册到,或者叫呃,关联到我们的这个worker现在里面,当然这个register里面呢,它还有很多工作,因为他会去选到底把它放在我们这个worker,因为这个worker group下面有四个,它有这个char。你看他还会按根据他的一个业务逻逻辑来选嘛,看这里面是不是下面有八个呀,那到底我把这个child,就是把我当前这个char放到我这个char group里面的哪一个n I event group,它自己会有个算法,默认情况下呢,一般是这样子的,先放第一个,再放第二个,再放第三个,一般是这样做的,是不是以前我们讲过他有一个next方法,最终他需要个next方法来做这个事情。
21:10
我就不去追了,好吧,因为到这其实已经把这个事情讲的非常的清楚了。如果同学们有兴趣,自己再去追。好,我把这里面简单的梳理一下。针对我们这一个就是China read这个方法呢,它其实干了这么一件事情,首先把MG强转为China,实际上就是n I so China。添加nlck China的PI的handler,就是我们另方法中设置的China handler。然后呢,设置它相关的属性,将注册到char group上的一个。这个event group在这register里面做这个事情的,并添加一个监听器,同时我们也明确了char group就是我们main方法创建的worker group,刚才是不是已经给大家看的很清楚了。
22:00
看这地方1371376,这地方也是1376,没问题吧,好到此其实就是把我们刚才说的这个流程。就是刚才我们看的那个基本的示意图说完了,好,这一部分的,这一部分的这个分析先到这,那下面呢,我们还要继续追这个最好吧,来说我们这块先说到这。
我来说两句