00:00
好,那么关于整个咱们这一章呢,这个ttp的网络编程啊,我这块呢,就列这样的三个例题了,然后呢,这个课件当中,这边还有其他的一些题目,包括下边还有一些相关的一些代码啊,诶大家你要有兴趣呢,你就写一写,其实呢,这一章呢,咱们对大家要求呢并不高,诶主要的这个点呢,其实就是通信的一些基本的要素,这个大家清楚就可以了,所以这个代码呢,你要呃想写呢就写一写,不写呢就是熟悉熟悉啊,基于我们上一张I流呢,你知道呢,在网络当中啊,也有这个通信基本的这个啊,原理套路是什么样的就行了啊。然后这块的话呢,我还又我又留了一个这个代码,这个代码呢,你看你名字就知道叫聊天室是吧。这个呢,代码呢,我也就不带着大家去写啊,咱们就稍微呢带着大家看看这个代码就可以了,这个呢,相应来讲这个逻辑呢就要更复杂一些了,因为聊天室的话呢,肯定涉及到多个角色了。啊,而且呢,我们对于一个单独的呃,聊天室的一个个人来讲,他可以发数据,是不是也可以接数据啊。哎,你发是不是不影响你接。呃,反过来也一样啊,接呢不影响你发,所以这块我们用多个线程来做嘛。
01:02
所以这个程序呢,看着就会稍微的复杂一些,这呢我们带着大家呢,就稍微的把这个代码呢,给它剖析一下就可以了。OK啊好,那破译的话呢,首先这块涉及到我们客户端有服务端。注意啊,哎,我现在呢,比如说聊天室最起码得俩人吧。哎,那你说我们这个俩人指的是一个客户端,一个服务端吗。还是啥呀。对啊,对的是两个客户端。那服务端的角色是干嘛的呢?对诶叫中转信息是可以的,他就负责这个信息的一个接收和分派。是吧,接收,比如说你这个人叫AB,这个人叫BB呢,把这个数据呢,发出来,发给谁呢?发给服务端了,服务端呢做的事呢,就是把你这个数据呢,首先接收到,接收到以后呢,然后呢,他再分发给当前这个聊天室里边呢,所有的人,你自己发的,你自己是不是也能看得着。对,那如果要三个人的话呢,那就是B呢,发送这个数据呢,然后服务端接收到之后呢,他就分派给你,当年的聊天室里边有几个人,我就都发一下。
02:03
OK,别人呢也都是一样的,所以这是服务端的角色,所以大家一定要注意说呢,我们要有三个人呢,去进行通信,是有三个客户端,这个服务端呢,不是作为一个角色出现的。那首先呢,我们来看下这个客户端这块啊,是怎么来设计的。客户端这块呢,我们刚才也提到了一个点哈,说呢他呢可以发也可以接。啊,这块我们实际上就涉及到有两个线程啊。OK啊好,那首先的话呢,因为你涉及到要通信了,所以我们首先得有一个socket,创建一个socket,这呢就指明我们这个服务端的它的一个IP地址和端口号了。然后呢,这块我们就创建两个线程,一个线程呢,负责接。叫receive,一个线程呢,负责发啊,叫做send。那这块呢,我们是在同一个费当中实现的。OK,所以这块呢,我们是通过这个构造器的方式呢,把各自的啊,继承于thread的这个类的属性呢,给赋值了。哎,表明呢,就是他俩呢用的是同一个socket,然后各自呢都start,就是这块我们开始接了,呃,然后随后的话呢,我们也开始发了。
03:09
好这块呢,你看有一个代码,这个看能看懂吗。哎,整个呢,这个程序呢,从上往下走的时候呢,这是不是一个主线程啊。在主线程当中呢,我们把这个接收和这个发送的线程呢,都给提起来了,实际上这块我们能看到的算是有三个线程了。两个分线程,一个主线程,好,然后呢,这个代码一执行,就意味着我们这个主线程现在是不是就阻塞了。祖先人阻塞干嘛呢?因为主线城这块呢,做的事儿呢,就是把socket给关了,杨爱之呢,就是我们聊天室呢,可能有好几个人,其中呢这一个人呢,这不有这一个发的一个接的嘛。然后呢,诶,我们执行这个操作呢,就意味着我要退出这个聊天室了。是吧,诶我要退出了,我们才会去调用这个socket的一个close方法了,那什么时候去调它呢?就是我表明我不再发了。是吧,我不发了,哎,当然这个呢不发什么意思啊,就我们这个send的时候呢,里边呢,会写一个语句哈,如果你要写了一个BY。
04:04
拜拜是吧,哎表示呢,我这块我要退出了,这时候我们就结束这个循环,一结束循环呢,我们让整个这个run方法就结束,是不是咱们发的这样一个run。如果你要不写这个拜白的话,我们这个就一直呢,在这个while里边呢,去执行,就可以一直发信息,那就意味我们这个run呢,就结束不了吗。那就相当于你一直可以在聊天里边去聊天了,一旦呢,你这个客户端呢,你要写这个拜拜是吧,诶我这个外号循环呢一结束,诶我整个这个run方法结束了,Run方法一结束的话呢,这就意味着我们这个肾的这个线程就执行结束了。哎,你就意味着说我。想退出了是吧,这个主线上呢,再给你把这个socket关一下,就对应的你接你也接不了了。那就这样的情况啊。稍微的理解一下啊,然后呢,下边我们来看一下这个发,呃,这个发和这个接的这个事儿啊。这儿呢,就是使用构造器呢,跟我们这个做一个初始化的,那就是各自的这个run方法。对于咱们这个发来讲。
05:01
啊,发发送的数据来自于哪儿呢?来自于我们这个从控制台从这也好,或者从我们这个位置也好,你自己写的这个信息嘛,所以这块我们首先呢,还涉及到一个scanner这个使用了。哎,Scanner这不是从这个键盘那来获取这个输入的数据嘛,哎,然后呢,我们给他写出去,写出去的话呢,使用socket那调output stream写出据吗。诶,然后呢,这块我们写出去的话呢,诶我这用了一个叫打印流啊,因为呢,你一换行是吧,我一回车,哎,就是这一行就打出去了啊所以这块呢,我就把咱们这个output stream呢包到我们这个打印流里边了。诶,然后呢,你就可以一直呢去说呗,哎,自己的话,然后呢,首先通过我们这个scanner呢,获取一下你要说的话。诶获取完这话以后呢,然后呢,只要你不是这个拜拜是吧,我们这个循环就一直执行,然后通过我们这个呢,给他传输出去。这个这块呢,就是诶,就相当于他每次呢,就就打印这一行数据,就是你输入的这一行数据。他就给你打出去了。啊,只要你不换行是吧,这个耐克方法呢,就是以换行感恩。
06:04
来表示呢,我们输入的这个数据的一个结束啊,哎,比如说呢,像我们有时候用这个聊天室,它这个就这么长,然后你这块写的话比较多,就一直在这写呗,只要你点个回车表示换行了,整个呢,这一段话当时就相当一行一样就给你发出去了。啊OK啊行,这个呢,是咱们是不是从键盘接收了,然后给你发出去。啊,就做这个事儿,发完以后的话呢,你可以回过来呢,再去接着发,所以这个方法呢,是一个组合式的。啊,就是只要你有信息发,他就在这儿等着呢,是吧,你只要呢,诶写了信息之后一回车,哎,他就走下边这个事儿。OK啊行,这儿呢,是我们这个发,然后接收的话呢,其实就类似的啊,通过构造器呢,给这个so呢做一个初始化,然后呢接收嘛。通过我们这个socket,那是不是调一个input stream。那这就来接呗。好,那记完以后的话呢,我们要把它呢,是不是也显示出来呀,显示到哪呢?显示到控制台上面。
07:03
哎,那这块你看这怎么做的呢,这个呢,我把咱们这个input stream呢,放到咱们这个scanner里边了。啊,Scanner也可以接收input的,这个STEM参数是咱们以前的用system.in了,啊,这个呢是从服务端呢,发送过来的这个数据放到这里边,然后给大家打印出来了。啊,为啥这块接收完,我们直接不整个字节数组啥的接收呢,这块呢,我想企业呢,还是这个一行的这样一个效果啊。因为呢,这个咱们打印流你是输出流,那输出流怎么办呢?这块我也想调这个一行的这个效果呢,诶正好用这个scanner这个next line了,所以呢,我把它呢就放到这个anner这个里边。哎,表示呢,就是还是一行。啊,这样一个效果啊。好,这个呢,就是对于咱们其中的一个客户端,两个线程。完事了啊哎,这个一边说的话呢,其实这块我们在,呃,当前我这一章里边呢,提供了一个PPT哈。简单的来看,这里边儿有个图。
08:01
把这个图呢,我把它盯一下啊。诶,推过来。诶稍微的把它变小一点,那刚才呢,我们讲的呢,实际上是属于其中的一个客户端来讲,我们呢,提供了一个叫发送的一个线程,一个呢叫接收的线程。好没问题了啊,接着的话呢,咱们来看这个服务端,诶服务端这块我们看都需要做什么事啊。哎,这是我们这个server了啊,这个服务端这块呢,它的主要作用呢,就是来接收各个这个客户端了,所以呢,核心的点诶,首先呢,在你有了server socket的情况下呢,我们就调access方法了。表示呢,你可以接收的这个客户端这个socket了。哎,这个其实的话呢,我们对于服务端来讲,你是多人聊天了,假设呢,我们这有三个客户端。回头呢,我们就得是是不是来三份这个的运行是吧。诶,各自运行好,各自运行以后,然后呢,我们接收来自于客户端的这个socket,所以这个方法呢,其实我们要多次调了,你要有三个呢,其实得调三次,但咱也不知道你到底具体是几个呀,所以我只能写成叫标出了。
09:03
哎,就是我在这阻塞着啊,只要你来一个socket,我这块呢,就调这个accept就接收着你。这样的一个情况啊。啊,像这个都是基本点了啊,就不多说了,好,那么我们这个呢,服务端呢,就始终呢,开启开启你也不用担心,因为这个方法呢,它是也是一个叫阻塞式的方法。哎,那就意味着你不用担心说哎呀这不是个死循环嘛,不用不用担心哈,这块呢,就是当我们这块呢,没有soet过来的时候呢,我是不是就在这等着是吧。只要你有一个了,我马上就接收一个你。所以呢,第一个socket,如果说我们诶跟这个服务端的建立连接的时候呢,我们一接收,诶我就这块拿到你这个socket了,拿到以后干什么事儿呢?因为咱们不是还涉及到服务端呢,是不是把这个数据得分发给这个聊天室里边各个人,所以我得记录着是谁过来了是吧,所以这里边儿呢,我提供了一个叫做啊一一个这个list嘛。哎,我这提供了一个list,在我们这个服务器端,然后呢,只要你过来一个socket,我就把你放到咱们当前的这个数组里边。
10:04
所以第一个你过来了,我就放进去了,第二个你也建立连接,我也把你放进去,第三个也建连接,我也放进去,诶我就在这个release里边维护了,到底有几个客户端了。这就这个事儿。OK啊好,下边要做什么事呢?哎,这个你给我建立连接以后呢,比如说客户端一了建立连接以后呢,紧接着他是不是要发数据了。他发送的这个数据,假设呢,发了一个ABC。哎,这样的三个字符,那发送过来以后呢,我们这个服务端这块呢,要干啥事呢。第一个事儿,哎,其实已经说过了,是不是把它呢,放到我们这个数组里,哎,这个集合里边是吧,这是第一个事儿了啊,然后接下来呢。是不是要拿到你啊,发送过来的ABC啊。然后接着呢,把你这个发送过来的这个数据呢,是不是在发给你当天聊天室里边的各个人呢。哎,对的啊,好,这里边儿呢,你会发现呢,我没有在一个主线程当中去做。
11:04
主线程当中呢,只是负责呢,把你放到这个当前的数组里边。放进来之后呢,我就接着回到这个Y处这块,我接着等,可能别人还要连呢。啊,这个细节大家注意一下啊,就是说我这个呢,客户端过来接收完以后放到这里边儿了,按说呢,我拿着主线程,我接着让他获取这个数据,接着给别人发不得了吗?可以的,但是呢,你如果说这个我们再做,接下来的拿到你的这个数据,我再给别人去发,如果在这个过程当中有其他的这个客户端呢,还想连你。那你是不是就得等着把这个发完之后呢才能连了。这就占用咱们这个主主线上不就这一个线程吗。所以我们希望啥呢,就是我呢这个主线呢呢,只负责把你放到这个当前的这个。集合当中放进来之后的话呢,我就接着等着别人呢再去连我了。所以呢,至于说呢,你获取这里边儿数据的事儿呢,或者说就说这个分发这个事儿呢,我就又提供了一个线程。
12:01
所以你就看到我这儿呢,你看就多了一个是吧,这个线能干啥事儿呢,就是获取你当前连接的这个socket,然后把你这边数据呢,拿到之后呢,分发给别人嘛。哎,看这块儿呢,是不是又造了一个。积乘以二类的这样一个类嘛,这个类呢,刚才说了它主要做什么呢。对,主要呢负责诶,获取当前这个socket中的这个数据,然后呢,并分发给。哎,对,当前聊天室的。哎,聊天室的包括自己啊,哎,所有人员。哎,或者叫所有的这个客户端。就是他也发给自己,就是你发的信息,你在聊天室你也能看到。OK啊,诶,所以这块的话呢,就是首先呢,你获取这个socket中数据再分发,那我们得拿着这个socket,所以呢,你看这呢,我又把socket传进去了。啊,然后在这里边这不也有socket,然后这块呢,你就传过来,通过这个呢,做一个实例化嘛。
13:04
好,拿到以后呢,我们调四大方法,这不就是在你这个run方法里边,看你要干啥事,哎这块呢,你看我们还是拿这个socket,咱不是也写这个,嗯,题目一的时候呢,我们通过socket是不是也调过他的IP地址,获取他的这个。呃,And address对象获取IP地址给我们这个属性呢,也初始化了,这呢多了一句话啊,哎,就相当于呢说哎,比如说我们这个客户端一呢,现在它已经连接上了。诶连接上之后呢,已经放这儿了,然后code端二呢,诶这时候获取连接的时候呢,我们把它通过主线程放到这里边了,放进来之后呢,整个的呃,接着的话呢,这个分线程就是跑到这儿了哈,他做什么事儿呢?呃,这个客户端呢,一连接上之后呢,我们这时候呢,先你还没发信息呢,我们先发了个信息给当前的聊天室的所有人。说谁谁上线了。啊,说客户端二上线了啊,然后这块我就把你的IP呢写上去,相当于这块就发了一个消息啊。这个消息呢,等会儿再说。哎,发了个消息,然后呢,接下来呢,你不是要发信息给我吗?把你这个骚里边这个数据呢拿到。
14:05
啊,拿到之后呢,这块我们也体现了,就是这一行的一个效果,所以呢,我们就是哎使用转换流,哎把它转为一个reader了,然后呢,再使用这个b reader,主要呢,就想调这个read line的方法。所以你看这里边凡是我们调的时候都是体现这个一行一行的啊,Print stream啊,Scanner啊,包括buff reader啊,哎,都是一行一行的啊好把这个呢拿到。哎,这个拿到之后呢,这不就是你要发的数据嘛,然后再发给咱们当前这个聊天室里边的所有人。哎,就这样的情况啊,好,你要还有那接着发就行。然后最后的话呢,如果说你这块呢,你不发了,咱们不是这个客户端这块呢,他如果说了一个叫拜拜是吧。他发了一个这个的话的话呢,我们这个发送的这个线程发送这块呢,这不是这个well出就出来了,一出来它就close了,然后整个这个run呢就结束了,RUN1结束呢,说明你这个肾的这个线程要做的事不就结束了吗。
15:00
这个结束呢,你不就是执行这个召唤方法的时候,你结束了,我们这个主线程就是往下走了,然后呢,你socket就关了,SOCKET1关了,就你整个这个单独的客户端呢,其实就整个要断开连接了。啊,你一断开连接呢,这块的话呢,我们自然这个循环呢就出来了。就是你只要呢,没断开连接,这个呢,不是可以一直接吗。诶,只要你装个连接了,我自然而然的我就再发个信息给聊天室的所有人说呢,谁谁谁呢,掉线了,我要下线了。这样的一个情况。稍微的有点绕啊行,然后呢,下边我们来看一看这个他给整个聊天室的这个人发信息的这个事儿,这呢就是你发动的这个数据了,哎,这个方法呢,我们就在下边定义的。你发送过来这个信息啊,嗯,这个事儿怎么做呢,实际上呢,就是哎,我们给这个当前数组当中,这不都有各自的这个每个客户端的socket吗。然后给每一个socket的话呢,我们给它来一个输出流,然后给他发出去就行了啊,所以呢,便利一下我们当前的这个数组。诶,这底层是个数字的是个release啊,诶这个名呢叫他,然后呢,把它这里边的每一个socket呢,我们都遍历一下,然后拿着这个socket的话呢,我们获取个输出流,然后这边打印流的话,我们给他把信息写出去就可以了。
16:13
那就这样的思路。啊,这个line呢,就是我们还是体现叫打印一行一行是吧,这样个效果。行,我已经说完了哈。整个这块呢,大家可能觉得稍微的有点难度是吧。好,这呢也算是咱们多线程使用的一个场景啊,这个大家大家呢,做一个了解就行啊,下来的话呢,这个也可以呢,不去写了,下边咱们写完以后跑一跑呗。华语话呢,诶如果呢,咱们在这个idea当中啊,试图呢去运行一下,那我呢,先把这个服务器端呢先开启。啊,开启了啊,然后开启以后呢,这个服务端呢,你就不要关了,聊天室呢,这块就始终得开着啊现在的话呢,我们把这个客户端这块,呃,这块我们跑起来,下面呢,这块呢,就起了一个客户端了。啊,你看自己呢,上线了,这个能发呢,是因为服务端一直开着呢。
17:04
啊,这个呢,你一上来,然后呢,就群发,群发现在就你自己啊。然后呢,在第二洞去运行呢,有个尴尬之处呢,就是我们要想再起一个客户端的话呢,我们再去做一个run,或者你点这块也一样,它呢会提示我说。哎,说当前这个呢,你看现在还正在运行呢,说我们不支持呢,你并行的去执行。你必须呢,把当前这个给停掉之后呢,再执行。要这样的话呢,我们就开不了第二个客户端了是吧。哎,那这块我们只能是把他那先都关掉了,怎么办呢,这样啊。我把这两个代码CTRLC一下。诶,咱就放在咱们当前这个章里边了吧,诶CTRLV粘到这儿,然后呢,我们通过呢,多去运行一个命令行窗口来体现呢,我们就开多个客户端啊在这里边儿呢,有些代码呢,需要调一调,比如说首先呢,你把这个打开,咱们这时候呢,运行的时候呢,把这个包呢,你得去掉啊。这是一个第二的话呢,咱们呃,在命令行去运行的是JBK嘛。
18:03
所以这块我们先save一下,把这个位置改成叫NSI是吧。啊,这个呢,咱们目前改的是这个客户端的代码,然后把这个服务端呢打开。啊,也是这块呢,把它先注释掉。然后呢一下。哎,这个我们改成叫ni啊,保存一下。行,把这个字数机改一改,便于咱们在命令行这块去演示啊好,那下面呢,我们把这个服务端呢先开启,诶我们就在这个位置啊,CMD一下。看出来了啊,出来以后呢。在这是吧,Java c这个我们叫chat,一个server的一个test.java编译。然后呢,运行。哎,这么着呗。好,这时候我们这个服务端呢,就给砌起来了,记起来以后呢,我们就不用管它了啊,下边我们再来一个啊CMD一下。哎,让他呢,来充当我们的一个客户端。这块呢,我们去编一下咱们的。这个是吧。
19:00
加C。哎,Chat一个一个叫,哎,它的一个测试。啊,编译了,编译完以后的话呢,我们接着要去运行,运行你看清楚啊,嗯,这是一个类,这是一个类,咱们要运行的应该是这个是吧,这里边儿有这个相应的这个主方法了啊。知道吧。哎,然后它的一个test,诶,走起。这儿呢,是咱们相应的这样的一个客户端,我就给提起来了。行,这个呢,比如把它呢稍微的变小一点啊好这呢我就放到这儿了,然后接着我们再来一个客户端。OK啊,这个客户端的客户端的话呢,我就不用编译了啊,直接呢,已经编译好这个文件了,直接运行就行,知道吧,在呢是运行我们这样的一个class啊。Cat。哎,Client一个test是吧,他也会撤。这呢是一个客户端,然后呢,诶这块呢是一个客户端,这块呢就有两个客户端了。
20:01
嗯。诶这是左边的这右边了啊,你看我们这个右边呢,他不是后来了嘛,他后来这块呢,一上来,然后呢,诶你一上线了,我就发送给整个这个群里边这个所有人了,这块看到说谁上线了。诶直不过这块要注意的话呢,就是咱们这两个呢,都是127.0点点一了哈,就看着点绕,这是他自己这个话呢,是这个上线的时候呢,群发给这个聊天室的个人的哈,这是第一个人哈,比如这块呢,我们写一个说。哎,你好是吧。回车一下。这不自己说的吗?然后这块。没收着啊。自己的话,他怎么没收着呢?哎,过来了,这也太慢了。啊,能收着是吧,然后这个呢,来一个说。嗯。啊,这个嗯,你也好,比如来一个叫前辈吧。走起。发了。这,这也太慢了。
21:00
我们这里边儿也没有这个相应一些阻塞呀。这也太慢了。这怎么。是吧,这个我看看啊,来一个ABC。过去诶是好了是吧。123。拜拜,重来一遍啊。这个下线了是吧,这个你也拜拜吧,哎,都下线重跑一遍啊。这个呢,跑起来。这个跑起来。重新来,重新来啊,这个来一个你好。是吧?这还。还有情绪呢,是吧。嗯。哎,Hello,兔啊。诶,还写错了。啊。行,哎,这不就过来了是吧,哎这块呢,你就相应的之间去通信就可以了啊,然后呢,这个ABC123。哎,发过去这不就过来了吗?是吧,嗯ABC456暗语是吧。
22:00
啊行,就这样通信就行啊,你要是三个人的话,你就再起个客户端就行,这个呢,比如说我们要退出了,这给我来一个,哎,啊这个呢,他就退出了,然后这块呢,就说谁谁下线了,这个说的是他啊他呢现在还在,他还在呢,但是你现在发信息只能你自己接收。啊,因为呢,这个目前呢,我们这个就你自己了啊,然后这个你也掰一下吧。那就这样啊。好,这呢,就是我们一个聊天室的一个通讯的一个功能,就这样的去写啊。嗯,这呢,我们就说完了,这个说完之后呢,整个咱们关于这个ttp呢,就告一段落了。OK啊。
我来说两句