00:01
Net应用实例,群聊系统。我们前面把net的核心组件。把它讲解了,那现在呢,我们来看一个Nike应用实例,群聊系统。该群聊系统具体的要求是这样子的,编写一个net群聊系统,实现服务器端和客户端之间的数据简单通讯,非阻塞的。实现多人群聊。客户端这边呢,他要完成的功能是可以监测用户上线、离线,并实现消息的转发,也就是说比如说我这里有三个客户端。这边有个。那A客户端说了一句话,比如说叫hello,他把这个消息呢发送给server server可以把消息转发给B和C,并排除自己。对,但是你要说把这个消息发给自己呢,你可以把这句话,呃,把这个提示信息做一个修改也行。客户端这边呢,要通过China可以五阻塞的发送消息给其他所有的用户,同时可以接收其他用户发送消息。
01:08
发送消息呢,是由服务器端转发得到的。我们这个案例的目的是进一步理解nit非阻塞网络编程的机制。后面这一个幻灯片呢,就是我们这一个应用实例运行的效果。大家可以看到server端。他这边呢,可以提示服务器启动,可以提示某某某上线。啊,而且呢,他可以说我这里收到了某个消息,并进行转发。可以提示某人离线。这就是我们这一个群聊系统的基本的界面。那客户端这边呢,对他可以发消息,也可以接收别人给他发送的消息。就是。运行的效果,那现在呢?我们就开始来编写代码,打开idea。我们新建一个包。
02:00
我们新建一个包,叫group。Chad。我们先写服务器端哈,再写客户端,分成两个部分来写。好,我们写一个group。Group。Chat。Server。好呃,先把主方法先写到这,那在这里面我们要要定一些相关的属性,第一个呢,我们先把端口定好。这是我们的监听端口。好的,这是监听端口。那现在呢,我们这个监听端口完了过后,我们现在就可以写它的构造器了。对,我把各个器写好。这边group。构造器这边我们要把什么做一下呢?就是接收一个端口,对你的端口呢,是在构造group server的时候传进来的,好搜一下this.port等于你传进来的port。
03:02
这是我们的group chat server,那有了这个功能,我们再写一个方法,代表它在不运行啊,我们再写一个run方法。编写一个run方法,Run方法干什么呢?呃,处理对处理客户端的请求。没问题,那就开写public void public void run,咱们就写个run好的。那这个让里面我们要写什么东西呢?还是老规矩,首先创建,创建两个。哎,两个那个就是我们所说的线程线程组。现存组。好,第一个当然就是我们的boss,对不对,刚才讲过了。这边我们指定一个一吧为二。拿到我们这边就叫boss。Boss group。
04:00
没问题,这边名称呢,我们把它改一下哈,就叫event loop。那紧接着我们再看第二个呢,第二个呢,我们把它叫做worker。Worker group,那worker group呢,我们就采用默认的,让它有八个。有八个什么呀,有八个。Event loop。好,这是我们前面已经说过的,下呢,下边代码呢,我们就继续来编写哈。呃,要创建什么呢?该六一个server。Server什么呀,Boot没问题吧,然后呢,创建起来。取个名字咱们就叫。B了啊,简单一点。写到这边,我们继续往下写,就要开始进行一个链式编程,设置相关的这些个参数,配置一些相关的参数。第二,第一个呢,我把boss。放进去,Worker,放进去,然后再来trade channel。
05:06
对这些我就不解释啊,这是我们China的将来China这边服务器China用的时限内。那这一点我们就是NIO。No。Server。Socket channel class。好,继续,下一个呢,我们就写option option是不是前面我讲过就是China。刚才老师China。Option。点我们设置一些相应的,呃,这个参数,比如说第一个我们要设置的是搜。Backlog以前是不是讲过啊,这边我们还是老规矩,设一个128。点什么呢?再点child option对,我们还要设置什么呀。Channel。
06:01
哦。China option第二什么呢,它的这一个连接,连接呢,我们把它设置成一个,呃。Keep alive。Keep alive处。对,紧接着我们下面就要开始做这样一个工作了,Char handler加上我们的什么呀,给我们的这一个pipeline指定相关的handler,那这个handler呢,这次我们就还是按以前的一个思路,咱们就直接溜一个啊六。要什么呢?又一个叫做channel。啊对,China这面是不是应该是soet China。就前面已经讲过的。这边我们要去实,呃,重写一个方法,把这个方法呢给他实现一下。嗯,那这边有一个分号,写上号接着往下写。
07:02
下面应该怎么做呀?是不是要先获取到,获取到这个pipeline,是不是要写到pipeline啊pipeline。Pile。那。很好获取到,怎么获取到呢?就是C点排量。点位二。拿到这个pipeline,拿到这个pipeline以后,我们应该是通过pipeline往里面添加我们相关的这些处理器,那第一个处理器呢,我们取个名字叫decoder。因为现在呢,我们要去接收这个数据,所以说我会用到他提供的使俊使decoder。这也是一个handler。这是加一个相当于这是什么呢?我写一个注释啊,这是像。向pipeline里面增加。诶,像这个拍on像拍PE烂里面加入。加入一个什么呀,加入一个解码器。
08:02
这是解码器。为什么呢?因为你将来发送来的这些数据我要通,我要进行一个解码,同样呢,我再加一个什么呀,在向拍拍里面加入一个编码器,为什么呢?因为将来我回收的时候,我还要进行一个编码。说我这写个编码器这两个。处理器呢,都是net自自带的,说last,再来一个encoder。好,六一个是俊。实施什么呀,N口就可以了。然后呢,是不是还要加入我们自己的一个handle啊,我们加入。加入自己的什么呀?Handler业务处理业务处理handler。好处理看。好的,那拍pe.add next,但是现在没有写,先写一个空给它占一下,把这个位置先占到好,这是这段代码,当时启动的时候怎么怎么启动呢,启动的时候其实也非常简单哈,启动的时候呢,我们就这样写。
09:08
嗯,好,这这边还这边启,启动的时候,如果说我们要启动,那肯定就是六一个这个是吧,就六。然后呢,指定一个端口,比如是7000。点启动的时候把这个写上。写上过后呢,我们掉这run就可以了。好,这边代码我们还没写完,这边只是把什么呀,把这一个。Server boot相关的配置做完了,接着继续往下写,嗯,那这里呢,我就可以提示一句话。我说什么呀,Lett Lett服务器干干什么呢?啊,就是就是说它启动。其中我们加加一句话,怎么加呢。就是我们的这个B点半。把端口写上port。对,在。
10:01
写一个SYC做异步的处理VR,它会返回一个什么?同学们是不是返回一个future?以前我们是用过这个China future。对这边呢,就会有一个什么呀,异常好异常呢,我这里简单处理一下,就直接从这里扔出去。Shop。好,接着往下继续写。那现在呢,这边你服务器就启动,启动完了过后是不是我们仍要去监听。监听什么呢?关闭世界就是参与了。关闭世界,关闭。好,那这句话应该怎么写呢?就是我们China future.close future。点什么呀?找到我们的channel点什么呢?close.sc好,也是做异步处理。好,那这边呢,大家都知道我们。这两个线程组呢,将来都会需要关闭的,所以说。
11:03
不管最后是怎么样子,都要关闭,因此呢,我踹一下,把这段代码写的踹起来。TRY起来,过去加个finally,最终呢,我是要关闭的,对不对,我先写个Bo。老下蛋,Grace。The worker group shutdown,好。代码就这样子的,那同学们看到这边呢,他说也有一个异常,是不是我们也要抛出去啊,因为你让你让的时候是抛出一个异常,那么这边我们也把这个异常抛出去就可以了。好,也是服务器端这一块咱就写完了,写完过后是不是要去写,这里面最关键的自己的业务处理还在那。是不是好,现在老师开始写这个handle。那就叫什么呢。Chad server。Hand。好的,那同学们回想回想一下,关于我们这个handler,是不是首先要去继承什么呀?我们写一个simple。
12:06
啊,Simple channel inbound handler,那这边我们在进行这个数据处理的时候呢,用string,就是在发送数据的时候,我们是按字符串来发送的,同样要重写它的一个方法,实现它的一个方法。就这个read啊,China read0,那同学们看到这里面呢,就回到我们原先讲解的ni的这个位置了,就是这个handle,那同学们想。我们我们在这个地方要做什么处理。是不是根据这边的要求。服务器端会接收到各个客户端发送的消息,我还要转发,比如说这边呢,会有多个客户端。对,那你想你要有多个客户端,你是不是在服务器端至少有一个,呃,有一个集合来管理。
13:00
这些客户端的通道是不是所以说呢。我们在这里呢,先来写到这,写个东西,写到哪里呢?我在这里先定义。啊,先定义一个什么呢,叫做China组。这是ni提供的。Let提供的一个类可以做这个第第一个China组干什么呢?管理。管理所有的所有的China。对吧,因为你只有拿到所有的China,你才能把数据进行一个转发,那这个时候我们怎么写呢?PRIVATE1定要加上static克。大家都知道我们的handle呢,是每一个客户端都会有自己独立的handleler,因此呢,这一个线程组其实是所有的handleler,或者说是所有的这个客户共享的这个线程组,那应该加上static,那就写东西了,那这边呢,我们这样做啊,就。
14:01
呃,就这样写China group。The channel。Channel。Group啊,有这样一个东西,那这边我们就留一个吧,这边就取个名字也叫China group。等于,等于什么呢?六一个default。T China group,对,然后这里面呢,我们需要有一个全局的事件执行器,叫什么呢?我给大家说一下。应该怎么写啊,Global global就它点instance。我先解释一下这是什么东西。这是听这个名字就知道是个全局事件执行器,意思是说明我们这边填入的是一个什么呢?是一个单例,它是一个单例。啊,是什么呢?是一个全局的事件。事件。事件。
15:04
事件执行器。是什么呢?是一个单例。是个单例,他是干什么,就帮过来这个执行器,就帮助我们来执行这一个China group,那现在拿到这个东西过后,下一步我们在返回的时候,大家也看到了,整个这边会有一个时间啊,有时候我会拿到这个时间,拿到这个时间呢,我们也创建一个对象哈,来走一个simple。有六一个simple。Symbol什么呢?Data data format里面呢,我们写上它的一个时间的形式。我就写年月日,十分秒年是不是?这样子的年月。日应该有印象吧,DD这小写的DD啊,我就不解释了,小时。分钟MM。秒好,拿到返回这么一个对象。
16:02
这地方。看一下啊,这边地方我们用这个接收一下吧,Simple。好搜一下,然后这边我们写个SDF等于好。这就OK了。这个用来干什么的呢?就是将来用来去输出时间啊,就是输出我接收到消息的时间,或者是或者是其他一些关于时间处理需要的时候,我们就用这个对象。好,下面呢,我们就继续开始写,大家回想回想一下,因为在这里呢,我有一个动作是要知道,就是嗯,客户端。客户端什么时候加入了?就是你看这里面,我们在返回的时候会知道客户端,就说我想知道是什么呢,他上线了,他离线了,我还想知道什么呢?我还想知道就是我们这个这个圈,这个客户端什么时候加入到了我们这一个圈组里面去,所以我需要先写一个,先重写第一个方法一步步来,里面有个叫做handler。
17:06
Addd。往下走,就它其实这个方法是第一,第一个被调用的方法是这个方法我写到这啊,就是一表示这个handle ID,它是第一个被调用的是什么呢?就是当。注意听,当连接,当连接。它表示什么呀,表示连接建立。建立。建立啊,就一旦建立了,过后一旦建立。一旦连接。一旦连接。一旦连接干什么呢?第一个被执行。第一个被执行就是在这里执行,那我在这里要做件什么事情呢?我希望在handler艾艾的被触发的时候,我就把这一个关联的China加入到我们的这一个China组里面去,明白我的意思吧,好,这里面我要完成一个任务是干什么呢?注意,就是将。
18:08
将channel就当前这个channel这样说,将当前这个channel当前。干什么,当前强者加入到,诶加入到。加入到哪里呢?加入到我们这个China group,好,那我就开始写这个这句话啊,呃,首先呢,我先获取到这个China cx。C。拿到。拿到这个当前这个channel,拿到这个当前这个channel过后呢,我就准备加到我们这个group里面去。对,就说这个China group呢,它可以维护或者说呃,管理我们所有的China,明白这意思,那就艾他看到没有艾方法是不是直接把这个China放进去就可以了。这里加进去了,就是来一个加一个,来一个加一个,那么我在这个地方加入之前呢,我希望能够干什么呢?把这个某个客户端加进去的消息推送给我们所有的客户端,我再这样写一句话,就是将。
19:10
将该客户,该客户呃客户呃,就是加入加入聊天,聊天的信息,信息推送推送给什么呢?其他在线的。在线的客户客户端。客户,那这个地方我应该怎么写呢?非常的简单,一句话就可以搞定了啊,大家看不需要你便利不需要便利,大家可能会觉得,诶,我应该便利一下这个China group,然后呢,把它里面每一个China拿出来再发送,没有必要它这里面有个特别好用的方法,大家可以看到点什么呢?Right and flash。这边我就这样提示一句话就可以了,怎么提示呢,我说这样写客户端,把他的信息拿出来。加什么呢,Channel?
20:01
点。Address,然后。再加一化。加入聊天。加入。聊天。好,来一个换行,那有些同学老师这个这这句话什么意思啊,同学们这句话呢,我要稍微给大家解释一下,他是干什么的,就是group China group呢,这是一个,它是它本身是一个管理了所有的China,因此你在调这个right and flash的时候呢,其实它就会把它当前管理的所有的China都给你发一遍。诶,它本身自身就会去循环,对这个方法是干什么呢?就是就是该方法。该。该方法会。会将会将什么呢?会将China group。China group中。中。所有的所有的圈儿。
21:00
上的便利。便利并并发送。发送。发送什么呢?发送这个消息。这个消息,所以说呢,大家不需要自己再去便利了,知道吧,发送消息,因此我们无需自己便利我们。我们不需,不需要自己便利。自己不要再去遍历一遍了啊,它本身这里面底层它就会去便利拿到所有的China再去发送,所以说你所以说为什么我们用China group用起来比较简单呢。如果你自己再去写个集合,用个list来管理China group就比较麻烦了,有些人呢,他是这样写的,我多说一句,有些哥们他这样写的也可以,但是呢,比较麻烦,他这样写的啊,也是一个static。干什么呢?他这边写个呃,比如说他写了一个呃这样的类型list。List。那这个list里面呢,它放的就是China。诶,然后这边他说的是China chinas啊,然后。
22:02
呃,有没电了啊,没电了,快没电了,我处理一下。没电。好,呃,现现在可以了,现在可以了,有电。咱们继续讲,有些人是这样历史的,用个历史的里面呢,用个集合来管理啊,它是这样子,又有一个什么呀,List。A list,好,然后里边呢,这边放的是China。这样子,然后他是怎么做呢?他他来了,过来一个在这里把它加进去。呃,然后呢,在发出的时候,它遍历这个list里面的所channel,然后再调用呃,这个right and flash去做这个也可以,但是比较麻烦,所以说我这里呢,其实用的就是一个呃,来自提自己提供的China group更方便一点,好吧,就是我用的是这个方法。
23:09
好,接着呢,我们继续往下写,这是第一个调用的,那下面呢,我们是不是还有一个功能要去提示,呃,就是它上线了呀,那这个上线在哪个,哪个方法里面是最好使用的呢?应该是这个方法,同学们我们需要再重写一个方法。哪一个呢,就是channel。Active哦,China active在这个China active里面呢,我们就可以去提示他上线。好,我把这句话呢写一下。对,这个表示什么?我多说一句。好,呃,这边表示的是表示China。China处于啊,处于什么呢?处于一个活动的状态。活动状态。啊,这里我们就可以提示啊,提示什么呢?某某某某某上线。
24:01
对,申请这个这个信息呢,主要是给我们服务器看就可以了,当然你要把这个信息发送给客户端也是可以的,我这里就在服务器端提示一下就可以了,来加上这句话。嗯,同样我。我这样就就把他的这个地址打出来就可以了,好吧,那就这样写就行了。System。然后呢,我们就写把这个China拿到就CX。点channel。点什么呢?Mo地址提示一下这个信息我就在服务器这端打了一下,没有给其他客户端说,因为我在这上面已经说某某某加入聊天了吗,我没有必要把这个,把这个信息再再发送一遍就没有意义了,我就去上线了。好的。笑脸。对吧,这就是提示他上线,那么我们还有哪个呢?大家看是不是我们这里面还有一个信息,大家看有上线,是不是还有一个离线呢。
25:00
那什么时候咱们提示离线比较合理呢?有active显然就会有一个active。再把这个方法找到active在这里。对。那这个方法呢,就是这个方法会在什么时候触发,触发呢,就是当我们这个China处于一个非活动状态,处于不活动状态。的时候就会触发这个,那我们这边就提示什么呢?提示某某某下线了。好,我们在这里提示某某某离线或者下线。叫离线吧,比较好离线。好,那现在呢,我们在这个active里面就写上这么一句话就可以了,还是老规矩,用刚才这样一个输出,就是什么呢?拿到我们这个channel。China点。Address加上一句话,离线。Shut。那除了这个之之外,我们还需要什么呀?大家可以看到我们是不是还需要提示一句某某某离开这这个时候呢,也可以在哪里加一句话呢?同学们看,我们现在还有一个就是handler remove没有做处理,这有个handler。
26:15
爱的。我们再加一个方法。就是handler。Re remove在哪里呢?把电话写进去。好,这个地方呢,就是什么时候呢,表示断开连接或者断开连接。断开就是断开连接了。断开。断开连接会被触发,那如果说他一旦断开连接。这个handle被就会就会触发这个handle remove,那这里面我们就提示另外一句话。来,我们把这个信息就发给我们的所有的客户,说某某某,呃,离开了好吧,那这边我们就不用在。服务器提示了,我们就这样写TXT啊,Ctx点。
27:00
啊,那就不要这样子了,因因为我要把所有啊,我这样写一下。将什么呢?将。呃,将这个某某。某某。某某客户离开离开。离开信息,信息推送推送给呃,当前当当前在线的当前在线的客户。哎,这样子写客户。好,那非常简单,呃,我们还是把他的China拿到。把签证拿到。对,拿到这个China以后呢。我看看啊,这个时候。嗯,把这个拿到过后,我们就这样写就行了,然后用当前的China group,因为我要推送给所有,呃,当前所有在线的客户,那还是用China group.right and。对,这这个时候呢,我们仍然是提升了一句话,客户端。
28:00
对客户端谁呢?加上他的地址,那就是china.remove。再加上。一句话干什么呢,离开。你看了。好。这就是这么一回事情哈,这么一回事情。好,那这样子做完了以后呢,下一步我们要做的事情是什么呢?来同学们,我们下一步事情呢,注意啊,这个handle一旦执行了过后呢,同学们这个China的group size自动会就说这这这个handle remove呢,也会直接导致当前这个China从这个China group直接就给你取掉了,所以说你不需要再这样再做一下啊,有些同学说老师我需不需要这样做China group。对,然后呢,有个remove啊,不需要啊,他自己呢,就会就说他一旦触发这个China remove呢,他也自自己会把当前这个China从。
29:00
这个China group怎么样呢?直接给你去掉了,所以说待会呢,我们可以在这里看到,呃,每执行一次handle呢,我们这个China group大小也会呃减少同学们可以试一下,待会我们这也输一下啊,比如说我输一下就是当前这个China group的大小。就这样写China group。Size,因为会看到他会,呃,只要执行一次handler就会少一个,少的是哪一个呢?少的就是当前这一个,呃,这个channel,好的,我把它输出一下,那看一下都行,Group China group。点size。好,那同学们现在看看我们是不是有了一系列这个,呃,某某加入聊天有了,某某离开了也有了,某某上线了也有了,某某离线了也有了,是不是现在我们要开始真正处理这个东西了,转发是不是一直没处理啊?
30:00
是不是我们这边才是真正的读取数据,并且把读取的数据转发给。当前在线的所有人是这样子吧,同学们。好,那现在呢,我们就来开始编写这个最为核心的方法,其实也不多,代码好,我给他写写一下就行了,首先呢,我们仍然是获取到。获取到当前这个channel。哎,下面我做一个注释。读取数据。读取。读取数据。OK,那获取到当前这个China呢。点channel拿到。我有用哈,待会儿我有用,现在肯定我我现在就可以我。大家还记不记得我刚开始说一句话,就是我们在嗯发送。呃。就是。得到一个消息发送给其他用户的时候呢,我们需要把自己排除掉,或者说我们给自己提示的消息是不一样的,所以说我要分别处理,这时呢。这时我们便利一下。
31:02
便利China group那根据不同的情况回送不同的消息。A,根据什么呢?根据不同的情况回送回送。回送不同的消息。对,主要是要处理一个什么呢?处理自己的问题,就你自己呢,你不能说把你自己的信息原封不动的发回去是吧,就没有意义了嘛,所以说我现在就编辑一下China点它有个方法叫for each。For each,好的,For each,我们先取出来。取出来过后呢,这边处理一下,那这个时候我们怎么去处理呢,大家可以看到我说如果。你这个全闹。就如果它不等于CH。说明什么,说明你,呃,你当前便利到的这个CH,就是从这个China group里面取出来的这个China呢,并不是当前这个China,是不是这个就直接转发就行了啊,这个不是当前的China。
32:07
那就直接转发,直接。直接转发。或者说提示一下啊,就转发吧,转发消息,那转发消息呢,我这样提示他比较好开始写啊,那就是CH用当前这个这个通道。这是这个渠道,是取出来的通道,刚才说错了,是从这个China group,呃,取出来的某个客户的通道,然后用他的哪个方法呢?Right and flash提示一句话。其实这样一句话,客户。客户,然后把他的。把他的这个信息哈,呃,客户,然后China group。就是China。对,China。就是这个客户,哪个客户呢。就是就是你当前这个客户,你当前这个客户干什么呢?发了一个消息,是不是我把这个信息发给了这个China,是不是相当于说相当于说呃。
33:02
把你当前这个China的信息转发到了这个通道上。就当前这个China发出的信息转发到了这个圈上,但是我提示的信息是这个人发过来的,就就说是这个人发给你的。这这个不是,这不是当前这个吗?就是这个人他发送给这个CH,这个假设是AB客户的。对吧,这个是A客户的,就相当于说把A客户的信息转发给CH了。他就可以看到,好,我们继续往下写。加。加什么呢?诶就是他发送的消息发送。发送消息。发送消息。好了,那个消息内容是什么呢?诶消息内容是什么呢?显然就是你现在这个地方拿到的。是不是因为是字符串,直接把这拼过来,加上一个换行,为了好看加上一个换行写完了,那如果不是的话呢,如果是的话呢,如果当前这个China就是你取出来这个CH就跟这个CH相等,是不是就是你自己啊。
34:06
就是刚好你编辑到自己了,变到自己呢,我们提示信息稍微变一下。啊,我们说稍微变一下,怎么变呢?呃,就这样子,咱们就说自己发生了一个什么好吧,就自己。但你也可以不发送,就你也可以不给自己发送,你也可以给自己发送,直接把信息改一下,自己发送了什么,自己发送了那些,自己。发送了消息,诶把这个消息呢,给他回显一下就行了,还是MSG。加。没有地方,同学们其实相当于就是回想一下。回信。回想啊,自己发送的消息给自己先来了一下,我又回想了一下,好,这就是嗯,China read,那么我们还有一个地方也要处理一下,哪个方法呢?就是发生异常怎么办,是不是你要处理一下。
35:04
好,那么如果一旦发生了异常,我一般是在这里干什么呢?就关闭就可以了,关闭啊,关闭这个通道。关闭这个通道。关闭就行了。关闭咱们就C。点。C。Close。好吧,就关闭关闭通道。好的,那这样子呢,我们服务器端这个代码基本就基本上就写完了。基本上就写完了,只是这里面我没有用到这个,这个好像我没用到是吧。那如果说要用到的话呢,就在这个地方打一个时间就是客户端。呃,就这你在带的时候呢,把这个时间该带过去就行了,好吧,我这里就简化没有没有用这一个simple date of mind,同学们呢,自己可以在回送消息的时候。啊,不管是是提示信息还是转发的这个消息信息呢,你可以把这个时间也带上好吧,这个自己去处理一下就行了。
36:03
好,那这块写完了以后呢,我们服务器端基本上就写完了,下面呢,我们就准备写客户端了。
我来说两句