00:01
Java bio的应用实例。我们来编写一个Java BI应用实例,来对bio的这个编程模型进行一个简单的回顾,待会呢,我们通过这个案例可以跟NIO进行一个比对。实例的要求是这样子的,使用bio模型编写一个服务器端。监听这个端口,当客户端连接的时候呢,咱们就启动一个线程与之通讯,对要求使用线程池机制进行一个改善,也就是说我们可以连接多个客户端,大家还记不记得我们在前面画了一个图。什么意思呢?就是说当有一个客户端来跟服务器进行连接的时候,我们就启动一个线程跟他进行通讯,再来一个客户端呢,我们再起一个线程与之通讯,以此类推,就是这样一个模型。第三点,服务器端可以接收客户端发送的数据,同学们注意到这里呢,他说的很清楚,在客户端咱们直接用tonight就这种方式发送数据就可以了,也就是说客户端这块呢,我们不专门的编写。
01:15
因为我们这里主要是来验证bio模型,Bio模型它是有一个连接,就起个线程,主要是主要是来验证这样一个机制哈,所以说呢,客户端这块呢,我们不单独的编写了,待会儿呢,我们直接用tonight。Tonight来连接就可以了。并且可以发送数据,当然你这边发一个数据过后呢,这边给他回一个数据好的。实例的介绍我们就说完了,我们现在开始来编这个小项目。好,我们点一下六一个project就建项目。Come。com.at硅谷点ninetyt,因为为什么我这写个net呢,因为后面咱们呢,呃,就是呃,除了这个代码过后,除了这个这个工呃应用实例过后呢,我们还会写很多其他应用实例,我们都干脆放在一个工程里面就完事了,所以直接取个名叫nit就行了,Nity project。
02:20
Next一下。Finish。OK,现在呢,我们找到。Java,然后新建一个包。com.at硅谷点什么呢?Bio,现在我们写的一个小项目是bio模型的,所以就写个bio。在这里呢,我们新建一个Java,取个名字叫bio server。同学们看一下哈,就是在这里我们编写这个bio呢,我们把一个简单的思路来做一个分析,因为在这里他已经说出要求我们使用线程词机制。
03:10
是不是他要求使用线程池机制,所以说我们的思路这样子哈,第一步呢,我们先创建一个线程池。诶,这儿写错了。我们先创建一个线程池。线程池,OK,第二步呢?干什么呢?如果有客户端连接了。就创建一个线程,创建一个线程与之通讯,与之通讯。好的,那这里呢,我们说宇宙通讯这块呢,我们专门的写一个函数。哦,单独的。单独写一个方法,OK,大概就是这么一个意思,好,同学们,那现在我们开始根据思路来编写就行了。
04:06
首先呢,我们用executor。S点我六一个线程词。好的。分配一个变量就是ex service。通过这个execuor service呢,我们来做一个什么事情呢?来看一下,我们就来创建,紧接着我们在创建一个server什么呀,Shocked是不是前面已经说过这样一个简单,就是六一个server。Socket。Serverer r v v。在这里面我们写上监听的端口666。是不是同样我们也分配一个变量。就这个吧,就叫server circuit,那这里面会有什么呀,大家看到他会说抛出一个异常,那这个异常呢,我们简单在这处理一下就可以了。
05:06
把这个异常扔出去。好,那么创建了server过后,下一步我们该干什么呢?我们在这里给他提示一句话,对,其实这样一句话说,服务器启动了。服务器一旦启动,我们就用一个外循环,因为这块呢,对我们学过Java的同学来说,还是非常简单的,说说我这里就稍微的快一点哈,我们就首先呢在这里。进行一个什么监听。对,监听。监听。监听干什么呢,等待。等待。等待客户端客户端连接。还记得吧?那怎么监听呢?进入server socket,是不是前面有个server socket。D accept。
06:02
点except这个点except它会也会返回一个变量,是不是返回一个socket,还有印象吧,像soet我们就叫socket,对,但是这边我们把这个变量呢,做成发量类型的,让它不可改。下面应该怎么办呢?我就提示另外一句话,说有客户端连接,连接到一个客户端了没有问题吧?很简单,就是说你这边是一个server socket,那么server socket呢?通过accept等待客户端连接,一旦连接成功,就得到一个so,这个socket就是。我们。可以相相互通讯的啊,这边是socket。拿到这个circuit以后,下面我们又怎么做呢?是不是启动一个线程的,该来看这里,咱们就创建一个线程与之通讯。怎么起一个线程呢?同学们非常的简单,因为我们这边已经有一个线程池了,还记得吧,这边有个线程池,这个线程池咱们换一个名字吧,这个名字不太不太形象,咱们就叫。
07:08
咱们就叫这个名字。啊,更形象一点。叫new catch thread pool啊这线程池,那这个线程池怎么启动一个线程呢?非常的简单点执行,大家看这个执行方法里面可以传入一个level。那么我们就给它直接在这里创建一个label。的一个实现对象里面呢,我们要重写这里啊,这里这个wrong方法我们可以重写,我们可以重写一下。Run方法,那刚才老师已经讲了,这个地方就是可以和什么呢,可以和可以和客户端,客户端通讯的。是不是在这里写啊,但是因为你这个客户端通讯的时候呢,有数据的发送,还有回复,我们呢,干脆单独的写一个方法放在这就可以了,因此呢,我的代码呢,就在这专门写一个方法来写。
08:10
那现在呢,我们在。哪里写一个监督方法呢?简单哈,咱们这样子。咱们就在这儿下面写一个。编写一个方法,编写一个handler方法。干什么呢?和客户端通讯。就这样子的,非常的简单。那现在我们开始写这个方法了,那就public,我们写一个static的好吧,那调起来比较方便,Void。算什么呢?就叫hander。我们看取个名字叫汉字吧。Handler,简单一点。那么你在进行让我跟客户端,就是你服务器端和和客户端通讯的时候呢,你应该给我传一个什么过来呢,你得把这个socket传给我。是不是没有socket,我没办法通讯,所以说socket拿到了。
09:01
烧拿到过后,下面我们就用一个踹方法把它包起来,因为这边可能会有异常发生。大家可以先写一写,写一写,待会再把它揣起来,我们先干什么呢?六一个BY的数组,大家回忆一下以前是怎么写的好吧,六一个的数组。这个BY的数组呢,我们指定一个大小。By newb数组,我们比如说就叫1024吧。10246。分配一个就叫bits,这个是一个BY的数组,到时间呢,可以用来接收数据啊,接收数据下面呢,我们再通过通过so。就是通过这个获取什么呢?获取一个输入流。因为我要去读取嘛,当然我就是输入流,我从这个管道里面来读取数据,我们就叫输入流,怎么获取到呢?通过so.get input stream。
10:05
还有印象哈料。拿一个这边呢,我们取个名字就叫input stream。这里面看到,因为涉及到IO操作,它往往都会有异常抛出,所以说呢,这块呢,我们用TRY给它包起来。出来,然后呢,这边一个catch。对把异常进行一个补货。补货过后呢,我们把异常的信息给输出来一下,诶这边少了一个一对不对,很简单代码。没有没有任何难度哈,现在是最后呢,我们还是finally一下,Finally干什么呀,我们这里面是不是,呃,不管你在操作的时候有没有发生异常,是不是我们应该把相关的这个socket。怎么样,给它关闭了没问题吧,所以说我这提示一句话干什么呢?诶我们提示这样一句话关闭。
11:02
关闭什么呀,关闭和connect的连接。那你关闭可能连接说白了其实就是把我们这个关闭了就可以了,Close。是不是,但是关闭这个so的时候呢,又会。抛出异常怎么办?再踹一下就可以了。对,然后呢,Catch。Exception e。1.p输出。好,咱们就写完哈,那大家接着往下看了,你这里获取到输入流,也就是说相当于你在服务器这端。在服务器端,通过这个socket,我们得到了这一个,这得到一个输入流,输入流就可以读取这个管道里面的数据嘛,是不是,那我怎么去读取呢?很简单,咱们这样去读取非常简单,这样写就行了,因为我不知道他会发多少数据过来,所以说呢,我在这里肯定是一个循环读取。
12:04
是不是循环的读取客户端发送的数据能理解哈,那就是我要。肯定是个外外语句。错。怎么读呢?非常简单啊,Input stream.read你看这个read的方法是不是是一个。重载的呀,那我们要把数据读到哪里去呢?读到这个bites里面去。对不对,那读完了过后,是不是它会返回你读取的一个数据的量哈,我们就取个叫read吧。这边会返回我到底读了多少个数据,那读了多少个数据,怎么什么情况下才表示我们这个数据。嗯,读取完毕了呢。怎么样才表示数据读取完毕了呢?就是如果说我们这个read。
13:02
它不等于负一。不等于负一说明什么?说明我们现在还可以继续读。是不是还可以继续读,如果他可以继续读的话呢,我们就把这个数据输出来,我们看看这是获取读取到什么数据输出客户端。客户端发送的数据。好吧。客户端发送的数据,那现在我们怎么去把数据输出来呢?因为你现在已经把数据读到了BAT里边,而BAS是字节数组,所以说我们把字节数组转成字符串就可以了。怎么把字节转成字符串呢?非常的简单。六一个是句。对不啦,又一个十菌,十菌里边我们写一个BY。这是我们要把它转的,从哪里开始呢?从零转这么多。
14:00
也就是说我我要把这一个字节数组从零下边为零的位置。直到read这个下标全部给他转成相应的字符串并输出。好的。嗯,那果说如果说我们已经read返回的就是一个负一,说明什么呢?说明我们这个就读取完毕了,读取完毕就可以break。是不是咱们这一次。就结束了,就这一次的这个通讯呢,就结束就break。退出来就可以了。这是我们这个判断的,那现现在想同学们,现在我们这一个方法就是你其实说白了,我这里就是干了一件什么事情呢,说白了就是我循环的读取客户端发送的数据,然后显示在客户端,显示在我们服务器端。这样一个功能。在run函数这边呢,我们就调这个handle。把什么传进去呢?把我们得出的socket传进去。
15:03
代码就写完了。代码行,我们现在可以来试一下,看看代码是不是能够正正正确的运行哈,来走一个。让一下。Run起来。咆哮。稍等。现在呢,服务器已经启动了,我们现在打开。一个命令窗口,然后呢,Tonight一下。TONIGHT127.0.0.1对,然后是666。好,同学们可以看到这里呢,它说连接到一个客端。现在我可以往里面发送一点数据,那么send怎么发送数据呢?我们先输入CTRL加一个中括号。
16:00
大家看我输入的是CTRL加一个中号,那这里面我就可以发数据了,比如说我输一个HELLO100回车,好同学们可以看到服务器这边呢,也就接收到哈。100了,我们再来三哈,200。诶,他又收到一个,那现在呢,我们再来起一个,同学们看我们再来起一个。客户端。Tonight。TONIGHT127.0.0.1是不是666。是不是他说又连接一个客户了。同样我们再往里面发数据,比如这次我发的是OK 100。我少了一个扇的。OK 100。回车是不是这边收到了OK100,我们再上的一个OK200。回车。是不是,所以说你看你。对应这张图,你来一个客户端,我就起个线程,你来一个客户端,我就起个线程给你通讯,那么怎么能够证明你每一个客户端是对应一个线程呢?
17:11
好,现在为了证明这个观点呢,同学们,我们在这里输出现成的ID和他的名字就能证明了。来,同学们看。同学们看,这个流程其实是我们在这里死循环监听端口。监听端口如果有一个连接到这儿呢,我们就。就就可以去得到一个soet这个socket。这个socket就是跟谁呢?就是跟这个客户端通讯的。对,所以说我在这呢,来拿到一个线程,我们在这里输入输出这个线程的,呃,它的一个名称,比如说我在这输。好,我们来看看此时此刻通讯的线程信息是什么哈,线程。信息。首先我们说ID等于。
18:02
我们把当前进行通讯的这个线程。的ID输出来,点get ID。再把他的名字输出来没问题吧,因为县城呢,还有个名字。等于我们再来夹一个,还是thread.current.get name。说你来一个,我们就连一个。对,那么再读取数据的时候,我们也把这一个当前的信息也打印出来。这句话的我我也就是说我想在我想看一下,它一旦得到一个连接以后,产生一个线程,这个线程是不是也是跟他进行通讯的这个线程。能理解我的意思吧,因为我们要证明一下这个观点嘛,好的同学们,我们再次启动。我们再次启动。好,启动起来了。
19:00
也就现在我们来看,是不是一跟我们分析的这个模式是一样的,同学们现在呢,我们在。进行一个处理,我们再tonight一下。连上去。同学们看,这一次呢,他。打出现在的ID是幺幺,名字是red,你为什么输出两输出了两次呀,同学们是不是你连接上的时候,你你在这地么,一旦连接过后就掉了这个handler。因为你这个except一旦。一旦这个监听成功了,过后得到一个soet,它就进入创建了一个线程,就调用了handle,他就先执行这句话。是不是就输出了这个信息,紧接着在这个while里面是不是又输出了一个信息啊。所以它会输出两次,那现在呢,我们来往里面放点数据。好的,Send看清楚了,散哈。Hello。
20:00
哈,100回车。还有同学们看到。再输哈100的时候,它这一个线程就是你刚才得到这个线程ID11的,我们再输一点数据进去哈200。我在发的时候呢,线程还是我们这一个ID为11的线程,没有问题吧,也就是说你只要这个窗口没有关闭,你就不停的发就可以了。而在整个通讯的过程中就是使用的呃,同一个线程,那现在呢,我们再来连接一个。好,我把这个呢。再连一个。好,Tonight,这是一个新的客户端,同学们看清楚了,新客户端连上去。这个客户端连上以后,同学们可以看到它这里呢,说有连接到一个客户端,这时产生了一个新的线程。也就是说,相当于说这又产生一个新的线程。编号为12,那同学们看,我们又来给他发数据。
21:00
好善的。我们这次呢,为了一次区别就叫OK100。那么我们再输,呃,在发送OK100的时候,它用的就应该是10ID为12的这个线程是不是这样子的呢?我发现的确如此,看OK142的。我们再发一个啊,同学们,OK 200的。是不是还是。编,呃,这个ID为12的,那换过来我们再输一个。哈,400是不是,他又用的是编号为11的。这个线程的,因此它是有可以区分的,可以区分,所以说我们再次证明bio模型呢,就是你有多少个客户端,我就会产生多少个线程,第二个还要跟大家说一下,就是我们这accept。这个except呢,它会阻塞,就是如果这个客户端它没有得到,嗯,一个客户端连接,它会阻塞在这里,什么事情都干不了,还有一点就是red。
22:00
这个地方也会阻塞。他在soed,他在去get,他再去读取哈,就是这里啊,啊在这在这input stream,他在去read的时候呢,如果说这个管道,或者说这个shocket没有数据读到,它会阻塞在这里。对不对,它会阻塞在这里,我们看是不是这样子的呢,我们看是不是这样子的啊,为了嗯,看到这个效果呢,我们先关闭一下,我们就用一个线程来玩,因为两个线程同时看呢,看起来比较呃,不太清晰,我们把数据先卡这。好在这里。好,同学们看我在输出这里叫啊。等待。等待连接,就说我们来理解一下什么叫阻塞。因为你只有把这个理解清楚了过后呢,我们在后面讲n nio的时候做一个对比,你才能够有一个比较清晰的认识,才能把它的模型搞清楚。好,等待连接,好,那现在呢,我们在这里再来一个read,在这read呢,我们也打一句话。
23:04
叫呃,等待读呃,Read,我们就写个read哈。Read看它会不会卡在这里,就连接成功了以后。大家看连接成功连接的,如果没有连接上呢,它会卡在这个位置,连接上了以后呢,如果你没有数据发送,它会阻塞在这个位置,看看是不是这样子的,来朋友们,我们运行一把。好的。好,同学们可以看到现在呢,它主我们的服务器其实已经阻塞在这个位置了,你看多难受,也就是说只要没有客户端的连接,我就堵在这儿,我这个服务器任何事情其实都做不了,这就是阻塞。那现在呢,我们来连一个吧。我来领一个。好的,同学们看我开始连接。哎,同学们看,当我们连接过后,它又阻塞在哪里呢?
24:01
是不是,呃,你看这边为什么又打了一个等待连接,因为你连接上了以后呢,对于这个主线程而言,对上面这个主线程而言,它是已经通过了,通过了过后它创建一个线程又。这个线这个这个主线程呢,会回到这边来。啊,如果说你有兴趣,你在这再打一个线程,其实是另外一个线程。啊OK,它相当于说有一个soet拿到过后,他就创建了一个线程,然后呢,他又回到这,在这个主线程这块呢,他又except在这里卡在这了。卡在这里呢,因为你这里没有,呃,在对于对于已经创建好的这个连接而言呢,它卡在这个read read这个方法的,因为没有数据发送过来嘛,所以说你看它这里卡在这的。Read。看到没有?好,如果我们发一个数据呢,也也就是说,如果在这个客户端没有发数据的时候,它一直卡在这。你看这是非常难受的一件事情,对不对,性能很低。
25:02
就叫阻塞。你看我发一个数据善。我来发一个send hello,一百一回车过后呢,这个read它就读到了,读到过后呢,它它又去卡在又阻塞在readid这个地方。看到没有,所以他很他很这个效率肯定是不高的,效率不高的,好的同学们,主车我们就说到这儿,同学们如果有兴趣的话呢,你们可以在这再打出一个线程,就是在哪里呢?在这个地方。在Y循环这个地方,你可以再把线程的信息打出来,你会发现这这个线程的ID应该是十,如果有兴趣的同学啊,我们可以试一下。我们在这儿再打一个信息出来。那运行一下看。看一下。其实也就是他现在有一个主线程。看这是不是主线程的。是不是主线程,主线程我们有一个连接过去过后呢,它产生一个新的线程,然后又回到主线程继续监听,你看。
26:02
是不是它,呃,它产生一个ID为11的,呃,创建了一个子线程,然后呢,又回到我们这个主线程继续进行监听,所以说有点类似于什么感觉呢,我们服务器端。这有一个线程。这个线程呢,呃,一一直处于监听的状态,如果你有一个客户端连接过来,我就给你产生一个子线程给你通讯,然后我又回到这个地方进行监听,你又来一个呢,呃,客户端,这个客户端呢,只跟我们主线程进行交互,那么主线程那呃得到你的连接过,又产生一个子线程给你通讯,主线程又回到监听的这个状态,好就这样一个逻辑,好的同学们,那关于。Bio的应用实例我们就讲到这,最后呢,我简单说一下他的问题之所在。那么bio模型其实编写起来还是比较简单的,大家可以看到逻辑很简单。但是它的问题是在哪里呢?第一个,每个请求都需要创建独立的线程与对应的客户端进行读,业务处理,还有数据的写,当并发数较大时,就需要创建大量线程来处理连接,系统资源占用较大。还有一点连接呃创创建以后呢,如果当前线程暂时没有数据可读,则线程就阻塞在阻塞在read操作上,造成线程资源的浪费。
27:23
当然有些同学会觉得,诶,那没有数据读取,我就阻塞在这里,不是挺好的一件事情吗?其实这样想就不对了,因为你没有读取,按理说我这个服务器可以做些其他的事情,但是你不能让我,但是现在这个传统的bio就是一直在这主主在这个地方,所以说这就是为什么NIO模型它是一种事件驱动的。为什么是事件驱动呢?当你有这个这个这个连接或者这个通道有事,有这个读或者写的事件了过后,我服务器才去,才去处理,这样呢,它的性能就会提升,提升很多,就跟我们说呃,这个点菜一样,人家这个没服务员没有把菜给你端上来,你就一直在这等,显然这是一种资源的浪费,好吧,好,同学们,那关于我们bio的应用实力就给大家聊到这里,大家好好的理解一下,尤其是这段代码。
28:14
尤其是这段代码,以及老师打印出的这些信息,大家好好的理解理解,这讲我们就说到这里。
我来说两句