00:02
IO网络应用实例群聊系统,前面呢,我们已经学习了IO的一些基本的理论。然后呢,他的一些运行机制,还有它的核心组件,我们已经说完了,现在呢我们来完成。基于NIO的群聊系统。我们先来看。该系统的具体要求。第一个。群聊系统实现服务器和客户端之间数据简单通讯,实现多人群聊。服务器端可以监测用户上线、离线并实现消息的转发。大家可以看到。这边呢,一就是我们的一个server端。下面这是一个客户端,这又是一个客户端,这又是一个客户端。同学们可以看到,当我们客户上线过后呢,我们可以拿到。该客户的。他的IP地址提示上限。
01:02
对吧,这是三个,那也就是说你有一个客户端上线了,或者说连接到我们服务器了,我们就提示。有客户端上线。第二个呢,我们可以看到服务器,呃,客户端这边可以发消息,比如说他说。呃,比如说这个地方这个客户端说我是50037,那么这句话呢,就会通过服务器的。消息中转发送到其他的所有在线的服务器,呃,客户端,你比如说你这说的50037,那么这边。就接收到了。到这这边这边也接收到了,看到没有。也接收到50037好,就是这么一个系统,当当然如果我们这一个客户端他离线了,比如说他关闭了程序,我们这边呢,就提示某某。某某客户离线,我们用IP表示就可以了,比如说你。
02:02
50037离线了,50046离线了,以此类推完成这样一个功能,那显然这边呢,分析完了过后,我们知道要写服务器端,还有客户端联名,两边都都要写,所以说我们怎么办呢,同学们。我们按照这个设计呢,我们就这样完成哈,我这里说看我的思路,这边是服务器端的一些信息提示,这是客户端的客户信息,呃提示,那这样子我们把这个图拿过去。我们对照这个图,这是我们的原理图。对,这这个图呢,同学们看到的这个图就是我们的一个界面图,或者说。功能示意图。那现在呢?我们就根据这两个图来编写代码。好的。我把这个稍微缩小一点哈。缩小一点。往这边挪动一下。待会我在写程序的时候呢,我们把它分成这么几个部分,因为这个程序呢,可能代码还是稍微有一点点多。
03:09
所以说我们把它分成这么几个呃阶段来写。第一部分我们。鲜血。先编写服务器端。对,然后呢,第二步我们编写什么呢?客户端在服务器这端呢,我们分成两步走,第一步编写什么呢?让这个服务器启动。并监听。监听一个端口,比如说我们端口是6667。第二步呢,要二第二步我们完成什么呢?服务器。对。服务器。服务器接收。他可以接收。接收客户端信息或者叫消息,并实现转发。实行转发。对。
04:00
当然了,嗯,在这里面呢,我们还得还得要处理,在整个这个过程,我们要处理他的这一个上线离线。对,他上线了,我们要给出相应提示,离线了要给出相应提示,客户端这边呢,相对比较简单,咱们就一步到位,所以说我们这块呢,分成三个部分来讲,这是第一个对第二个第三个明白。那所用到的知识就是咱们前面学的基于这个图的。呃,涉涉及到的相关组件,同学们打开idea,我们现在开始编写,为了跟前面这些有些区别呢,我们干脆呃新建,在下面建一个纸包group chat就叫群聊。好吧,那现在呢,我们先编写它的。服务器端。GT。Server。
05:02
编写开始好,主方法写上,主方写上了,我们这样子我们先怎么样,同学们,我们先去定义,对,我们先去定义相关的属性。定义属性,哪些属性是我们需要的,同学们想。在服务器这端是不是应该有我们的server?有我们的server socket。呃,Server channel,还有select这些端口是不是也要有啊?因此呢,我们先定义这么几个属性,Private,跟着我的思路。Select。这是必须要的。先放到这里,因为待会呢,我们可能有多个呃方法我们都会用到。好,紧接着继续往下写。引进去就可以了。对吧,引进去,然后我们再写private。
06:00
Server。Socked。Socket turn。对,然后呢,这边我们就写一个叫做这个,这个现在呢,我们取个名字叫listen,他是做监听,他专门做监听的。Listen。吧,用于监听,再来一个端口号,我们把它也定好,Private。Static端口号呢,我们不变化,所以说用静态final类型。PORT。我们指定监听端口6667,刚才我。这样已经说清楚了,好,现在有了它过后呢,我们现在开始写相关方法,这个主方法先不要写,先写构造器。哎,在构造器构造器,那构造器呢,我们就开始编写就可以了,Public。对,然后group。这个构造器里面完成一些相关的初始化任务,对吧,我们把初始化任务写这里。
07:02
初始化的,初始化的工作。哪些工作需要我们初始化呢?在这个构造器里边,我们完成初始化任务,那么我们这里面呢,来适当的处理一下它的异常。对,这个异常呢,大部分是IO异常,所以说我们捕获IO异常就可以了。对,输出来。那同学们看,那在这个异常里边有哪些东西我们要去。编写呢,我们来看一下哈。好走一个,首先呢,我们先得到选择器,没问题吧,选择器怎么获取,还有印象不是不是我们已经定义了sector这个属性,然后通过sector。点什么呀,Open就拿到了,紧接着呢,下一步我们该做什么工作呢?就应该。获取到或者叫初始化我们的server socket。
08:05
对,这边也很简单,怎么写呢,Server。Socket China an open。对吧,然后把它付给我们的ni。China。等于没问题,紧接着下一步该干什么事情呢?下一步绑定端口。绑定端口,绑定端口那也很简单,我们这样做就可以了,Listen listen channel.shocked.band。又一个啊,In need address里面写上我们的端口,端口前面已经定好了,就是6667。端口也绑定好下一步设置,设置非主摄。主摄模式不要忘了这句话啊,这句话要忘了的话会到时候会出问题,点configu。
09:02
Blocking,我们写个false。下一步做什么事情呢?好的,下一步就将该。就是把我们的这个listener。注册到。注册到select上,是不是老套路的select?Listen china.register我们注册到S上面去,然后我们关注的事件,显然现在是关注的是事件。Accept selection。Selection。Select key。点。Accept。如果有新的客户连接呢,我们就会把它下来上好这个地方,呃。代码就写完了,下边同学们,下边呢,我们就来完成监听的一段代码。好监听。
10:01
就说如果有客户端来连接了,我们怎么去处理。Public void什么呢?好的。立,那在这个历里面肯定是一个循环,对不对,它肯定是个循环,所以说我们先把它踹一下。因为这边可能也会有异常发生,所以说我们把这些该做的工作,现在都把它写好。好,可能后面有个finally,先把这个框架搭好。那在整个这个过程中,我们在踹的这个过程中,肯定是一个循环的监听循环。循环处理。说说,我上来写一个外。处。那Y语句错,根据我们原先写的,是不是我们先去获取到这个,呃,有哪些事件发生应该用select.select。比如说我们。呃。
11:00
在这里。监听两秒,当然你这边如果不写的话就会阻塞,所以说我写个两秒,当然平时你不写也是可以的啊,我写个两秒吧。假如我们写个两秒,写个两秒过后呢,这边就会返回一个int。接收一下count等于。好的,我现在根据同学们,我现在根据什么呢?这边就会有异常发生了,对吧,有什么异常呢?有IO异常,那这次我们简单一点,直接用exception。如果有异常的话呢,我们这边进行一个简单的输出。那现在根据count返回的值来做相应的处理,如果count它大于零,说明有事件要处理。是吧,有事件处理,或者有有相关的channel通道要处理。有事件。处理。如果有实验处理,我们就往下走,如果没有的话,Else怎么办呢?咱们可以提示一句话。
12:04
提示,话说,等待。就是什么呢,等待中。等待。好的。大于零的情况下,我们下一步应该做什么事情,是不是要去进行一个便利了,要便利。便利得到的什么呀?Selection k集合。是不是前面也是这么做的呀,非常简单,Select点。Selected case点直接拿到迭代器。拿到这个迭代器了,拿到迭代器呢,显然我用这边再来一个while循环。点还有没有下一个。如果有下一个我们就继续处理,没有的话呢,就结束了。现在取出。取出这一个K。
13:01
OK,怎么取呢?是不是挺简单一件事情,特点,Next。就拿到了。我们就拿到这个K了,那这地方我们就取个名字就叫K就完了。那现在这个K到底是什么事件?我们叫做不同的处理来写段代码。如果说我们监听到了,跟上思路,监听到了是。ABT就是这个事件,连接事件。那现在呢,我们就来。进行连接的处理。如果是is。Acceptable。我们就去处理连接,处理连接是不是我们前面代码其实是在n IO server里面写过一次的,那如法炮制,写就写就可以了,那首先呢,我们先干什么呀。接听就是用accept来拿到,那这地方我们就用listen。点。
14:01
这边会返回一个什么呀,Socket channel是不是,那这边我们就叫取个名字叫做。SC吧,啊,比如说叫SC简写。好,继续继续拿到这个socket China过后,我们。应该怎么做了呢?是不是要注册了,将该SC注册到什么呀?Elect。是不是这个道理,怎么注册呢,SC点。一样的道理,这时呢,我们放的是还是他?然后我们关注的事件,我们这边关注的事件是read事件,手写成op read,如果将来有需要我去读的操作,我就。会去三四道。注册完这个刷过后,下面我们该干什么事情呢?我们就可以提示一句话了,提示什么呀,某某某上线了。
15:08
现在给出提示。大家看是不是在我们。的示意图里面这边有一个提示说。某某某上线了,我们拿到对方的。IP地址在提示上线就可以了,说出一句话。OK,简单的很,怎么做呢?我们现在不是已经有SC了吗?点get。这个remote address再加一句话就可以了,上线。好的代码就行了,这是我们的什么呀,这是我们的,呃,如果是。如果是is accept的时候呢,我们就这么去处理,但是你不要忘了一件事情也有可能它是什么呢?它是发生了读的事件,就是说有数据需要去读取,那又怎么办呢?我们as一下,As我们就干脆不A了,因为将来可能事情还有很多,我就再写一个衣服,如果这个K。
16:08
他现在是is。哦,就是要读读事件的,要读取数据了。Is readable可读的,现在呢,就说我们这个通道变成可读的状态了,你也可以这么去理解啊,就说可以这样理解说通道。通道发声,发声read。事件。或你也可以这样理解,即,即什么呢?即通道可读了。通道是可读的状态。可读。的状态,那既然是可读的状态,我们是不是就要从通道里面读数据到我们的buffer里面去,好,那下面代码呢,我们就。处理处理毒,呃,处理这个毒的毒的这个工作呢,待会我准备专门写一个方法,因为这面代码可能会多一点,就说我们会专门写方法。
17:05
专门写方法。好的,那同学们,那呃,具体这个方法怎么写,待会儿呢,我们会专门去专门去写啊,我们先空在这里,空在这里,我们现在把这做完了以后,这个方法待会再写,紧接着我们做一个处理,当我们把这个K进行了判断以后,下一步还有一个什么工作必须要去做呢?就要把当前的。当前的这个K从删除。删除啊,防止什么呀,防止重复处理,是不是前面我们也这么做过一次,还记得吗?打开这里看一下。是不是我们要处理完了过后也有一个移除的工作。哎,就是手动从集合中删除它,那同样我们把这句话拿过来用一下就行了。放到我们这边来一样的。好,把这个拿掉。那现在呢,不叫ker了,它就叫iterator。
18:02
Edit,我们把它放过来就行了。
我来说两句