00:01
好同学们,那么我们呢,就已经把刚才的第一个界面把它做出来了,但这个对对我们来说还是比较easy的啊,还是比较的,那下面这个地方大家看啊,东西一下都多了,我为什么把这些东西列出来,就是希望大家有一个整体的,就这第二个功能一下这个难度就上去了。就是有些同学可能一下就就会听听蒙圈,因为这里面有好多东西以前是大家没有怎么接触过的,那么还是老规矩,我先说一下我要做什么,然后呢,我再给他分析我的思路,然后再代码实现。首先呢,我们这次完成的是实现用户登录。实现用户登录。好,这是我们要实现的一个功能,先看清楚。那这个实现这个用户登录呢。理论,理论上来说这个东西。如果你要做的比较简单,其实很容易。
01:03
你把用户密码一拿,在后台一拿。拿到过后,你判断用户名密码对不对,返返回一个OK就可以了,但是这个呢,如果你这样处理这个思路,同学们,那你就是做的。小玩具,那实际上呢,我们要这么去做了。同学们看,现在老师就要开始说,我们这一个就是多人。多人聊天的聊天室的一个分析,就结构的一个分析。现在我们要做的一个功能是什么呢?大家看到了,就是实现一个登录,实现这个登录,如果说我们只是为了这实现这一个功能,其实特别简单。怎么简单呢,你这里假设是我们的客户端,现在我们来分析它的一个东西啊,同学们注意听这一个客户端吗?客户端。
02:02
然后呢,这边是我们的服务器端。这边是我们的服务器端。看清楚了,就是服务器,服务器端。OK,那现在如果仅仅是为了完成登录,非常简单,我把这个信息整理一下发过来。我把这个信息发过来过后,然后对方他这边服务器端他接收。他接收什么呢?你的用户的ID,肯定能够拿到用户的ID。但是你想想怎么拿,你肯定要去携程。你不能说来一个人,我就给你死死的,就就盯在这个地方,那肯定不行。第二个你接受用户名和密。还有密密,还有密码。当然,你还要去比较。对吧,比较。比较完了过后,你给他返回一个结果。返回结果,返回结果这边你给他打回来,你把这个结果给他打回来,那这边的代码呢,它其实它的这个最简单的意义就是说我发送我把就是他把他接收的,接收的用户的接接收的输入的ID和这个密码先拿到,然后第二给他发送。
03:23
发送这个ID和这个密码。注意听啊,同学们注意听老师思路。第三步,他接收。接收到服务器端。返回的,返回的这个结果。结果,然后判断是成功还是失败,并显示对应的界面。判断是成功还是失败。并显示。显示。显示对应的页面。大家看,如果只是一个简单的东西,就已经这么复杂了。
04:01
好几步拿到发送,发送你是不是要创建连接了,你创建连接过后,人家这边要在listen listen accept,然后比较,比较的时候,这地方肯定接收到过后肯定是一个。肯定是个GR,你不可能说还就一个单机版的那样去玩,你看这两头光这个就行,就很麻烦,但是这里面最麻烦的问题是什么地方,大家知道吗。最网络编程里面最麻烦的是这个数据的通道问题。这是最麻烦的,如果你做曾经做过这个数据通道。你做过这个服务器数据通道,你就知道这两根线很麻烦,他的麻烦不在于说你能不能把数据发过去,而是在于这个数据以什么形式发过去的问题。因为你将来发送的信息不仅仅是登录,你还有很多信息,比如说用户上线了,用户离线了,然后呢,用户上线过后,你服务器还得把所有用户在线信息群发给其他在线的用户。
05:05
那挺麻烦的,说你只是这种很单薄的一个结构,说我给他来一个字不算,根本撑不住。现在的问题就是我们要定协议。所以要把这个东西讲清楚,其实挺不容易,我昨天想了半天,昨天我昨天备课备的最累,我从早上九点钟背到晚上将近两三点钟,不相信你看我的这个东西两三点钟,我其实这个东西对我来说并不难,我都是要给你讲清楚,很难知道吗?因为这个东西就在想为什么诶,为什么要这么去设计呢?好,现在我们就要引出这个东西了,怎么设计,我就不不用这个简单的啊,简单我就不讲了,因为简单这个地方简单讲了过后反而容易搞懵,所以说现在呢,我们要设计一种东西,怎么让这个数据更合理,各位同学,现在我开始玩这个东西了,现在的关键点就是说我们数据以什么形式发送。关键的问题是啊,关键的问题是。
06:00
怎样怎样组织组织发送的,发送的这个数据。而且这里面还有麻烦事,你你发送的一定是个结构体。而结构体呢,又涉及到些序列化,序列化过后里面得到过后呢,它要反序列化,反序列过后它又给你生成一个新的新的一个那个messagec机,它又是个结构体,拿到过后你还要反序列化,序列化然后再回来,他还对方还要反序列化。你说这一下就麻烦了,好,现在同学先不要害怕啊,我先给你说的,这么害怕人呢,主要是引起大家重视,那现在我开始设计这个东西了,我要设计这个东西注意听。注意听啊,我们要设计。设计这个消息。协议。啊,那怎么设计呢?同学们看老师一画图你大致就明白了啊,通常情况下呢,在我们这个开发中呢,一般会采用这种比较通用的原则是这样子的。
07:01
走,这个地方是我的一个message。这个地方是我的一个结构体,Message,它是个结构体啊,肯定在这个开发中一定是用结构体,你不可能用一个串串啊,那串串那个小儿科那肯定用不了,所以说呢,我会设计这样一个东西。我就直接叫message。那么这个呢,它是一个结构体。它是一个结构体。啊,Structure我就简写啊,这是可能空间有点不够用了,那么这个结构体怎么做呢?一般来讲它把它分成两个部分,分成两个部分,第一个部分我们叫做消息的类型。对你消息是什么类型,因为你的消息可能很多类型,可能十种25,像像QQ像这种类型,我说少说少说不下100种。它的类型肯定不下100种类型,你发的是语音还是在线,还是离线,还是还是文本,还是那个图片等等,所以说他首先第一个大的有个type。
08:05
这个你跑不了。十寸类型的,你你肯定用十寸来描述他们,第二个朋友们,第二个同学们,我现在思路都要分析半天。啊,这是他第一第一个第二个呢,它有你你这个肯定有个。就说你你这个消息除了有类型之外,你是不是还有数据本身呢。你你光说哎,我要登录了,登录是一种消息类型,那你登录的时候,你肯定要带你的ID和用户密码吗。而且还要具有扩展性,没准下来下一次发的不是ID,密码还要带诶这个小朋友的好友是哪些?里面又涉及到一堆什么乱七八糟的东西,比如说他还是个map。所以这里面呢,它是数据也是类型,好,这是一个主的一个message,但是我们将来这个message会有很多,因此它的区别在哪里,就是说这是一个message,它是一个种类。
09:01
它是一个大的一个种类,但是我们每个消息呢,从哪里体现出来呢?第一个你将来这个地方,同学们就这个地方会有很多不同的种类。有很多不同种类的消息,而这个数据怎么体现呢?好数据里面呢,我们要重新再定义其他的消息,比如说各位朋友,假如注意听啊。假如这地方我有一个消息,我有一种消息叫什么叫叫登录消息,我就拿一个举例啊,拿多了你反而蒙圈。这是一个消息。这个消息呢,我们假设定义为叫登录message。Logging。Log这个是也是一个结构体,注意看这个也是个结构体。那么这个结构体里面呢,它可能就会根据你的实际情况来定它有哪些字段。它有哪些字段,注意听,也就是说这个结构体里面有哪些字段呢?诶咱们可以根据你的实际情况来定义,这是个ma,它是个结构体,比如说我们认为它应该有什么呢?有ID。
10:11
比较UID。那么它是类型的。它是特类型的,再比如说我们认为它还有什么呢?它有它的用户密码。是做类型的。当然还有很多其他,我就不一一的说了,到时间我们怎么样把这个消息和他整出去,因为我们还要另一个类型。就这。它是进行一个组装啊,同学们看这个地方呢,我们还要定义消息的各种类型。这个叫类型吧,叫消息类型。消息类型,那也就是说将来我们的消息。到底是哪种消息把它塞给这个type?把它塞给这个type,当然这个将来每一个消息这个结构体序列化后,先序列化。
11:07
序列化后呢,把这个序列化后,这个东西呢,塞给怎么呢?塞给这个消息的data。消塞这个消息的data。好,最后你要其实说你在发消息之前,你要确定你发送消息的类型是什么,以及你发送消息的这个数据是什么,因为你虚化了,然后你相当于说你把这个序列化的这一部分塞给他的data,把它类型塞给的type,然后你在发送之前,各位同学先把这个家伙。虚得慌,但这个空间有点不够了啊。先把这个东西先序列化发送时的顺序,注意听讲发送时的时候顺序如此这般。好,为了好看呢,我给它来一个颜色。没有颜色造型我自己区分不了。
12:00
纯色的啊,我们先把思路分析清楚再写代码,不然的话,今天这个学习效果就达不到,而且呢,你听完了过后,我告诉你啊,你很有信心,你很有信心去写一些自己想做的东西,那么这方发送的顺序应该是怎样知道啊,注意听发送的这个顺序。发送的这个流程。第一步。第一步,先先创建。先创建一个message的结构体。但这个时候这个结构啊结构体,但这个时候这个结构体实际上是个空的,然后呢,你因为假设你要登录,我们就以登录为例啊,不不扯别的,扯多了麻烦,然后你第二步给他设置这个消息类型,这个消息类型呢,假设就是这个这个登录的消息。给他的这个message。点他的这个type,设置type,它设置一个什么呢?设置这个登录消息类型。
13:01
那这这个地方还没写完啊,第三步,第三步你把这边序列化的东西,假设我们这个序列化东西就是log message,然后把这个message点。序列化后的这个给它放进去。哪个呢?比如说就是登录消息的内容,登录消息内容。登录消息的这个内容,但内容呢,现在已经是被序列化后的。像它就是序列化后的。序列化后的,那序列化后的呢,你现在还不能发,你第三步,你第你第四步,你要对这个message再进行序列化。对message再虚拟化,对就是对这个对这个,因为你把这个类类型给他了,输出给他,但是他是个结构体啊。它是个结构体,他也不能发,所以说你要对它进行序列化。那继续序列化过后,你是不是马上就发了也不行,在我们网络里面最害怕的一个东西就是丢包。
14:07
在网络里面最怕最担心的就是丢包问题。因为这个丢包一旦丢了后少了一个,比如少了一个自检,有可能导致整个这个程序你调不出来错误对不对,比如说因为网络的这个网络这个东西,比如说你发一个发一个文件过去,结果少了一两个字节,整个视频都打不开。整个视频都打开,你不相信,你试试看,你用那个,你用那个,像我们这个一般可以打开二进制那种叫a plus。或者有一个叫UN UN editor的什么东西,打开过后,你把那个视频打开,你把里面的文件删掉一个字母,整个文件就废了。所以说呢,你现在还有一个问题,就是防止丢包问题怎么处理呢?好就是防止丢包,这个在网络中啊,在网络中。在网络网络传输中,这其实已经虚拟化了,在网络传输中,传输中最最担心的最麻烦的啊,麻烦就是什么?就是丢包问题。
15:10
丢包问题,丢丢包。那丢包怎么解决呢?一般这个程序员是在我们程序里面是怎么解决的丢包的呢?我举个例子,同学们都上过网,你上过网的话,你们发现HTTP协议里面第一个有一个字段就是这个包有多长。就在content的。他一定会告诉服务器我这个包有多长,那个长度非常重要的。那个长度非常重要,因为它在发送之前。他在发送之前,他告诉你我这个message,或者我这个数据有多长,比如说是20个字节还是30个字节,那对方在那边一定要读到这么多字节,如果少读一个,他判断有错误,好读不到他就认为这个包。错,它会细胞再重新让它重放。
16:01
不然的话,这个网络你将来写的这个程序一定是会有很多bug,所以说我们这处理方法,我们就按照这个严格的一种方式,应该在发包,在网络传输第一步,先不要发这个message本身。先不要发这个message本身先发送,先给注意听啊,先给服务器发送,发送什么,这个message的这个长度,它的长度,它的长度及它有多少个字节。有多少个自己,多少个自己。好,这是他第一步要发的,他先把这个发过去,发过去过后他再发什么呢?他再发送。在发送这个消息体本身再再发送。在发送消息本身。好,这个发完了以后,这个发送的任务才算是完成。才算是完成,那么对方这边接收的流程又怎么样呢?接收的流程。
17:03
他是这样子的,他一旦他一旦要去接收你发送这个message,因为你这个message还是个支付串码,他首先先去判断我应该接收多少个自检。也是他先接受的是个长度。好,我们先看这一边这边流程啊。这边是接收的流程。哦,接收数据的流程,当然这边呢,它还涉及到一个反序量问题,还麻烦,他也很麻烦,因为你接收到的时候实际上是个Mac,但是你真正要的是谁呢?要的是这个东西,因为你只有通过他才能知道你的ID和密码是多少。对吧,所以它的流程是如此这般的啊,注意听。第一句话,第一句话首先我们先接收这个家伙,给我们发过来这个长度,比如说N。最近不着急啊。他要他先要发送这个N,而且发送的时候呢,还不以不能以int发送,还得以字节的形式发送程度还有一个麻烦事,但不管怎么样啊,先他先接收。
18:09
接收到这个客户端。客户端发送的这个这个长度。这个长度里面还有很多步骤,因为你接收这个长度不是真正的一个int,它是一个BY切片,你还得把BY切片转成的一个int。因为网络传输的时候不能以特。这种类型发送,它全是以什么呀,字节发送的,这就是为什么网络可以传输文件,传输图片,这个这个你明白了过后我可以这样说啊,你就是传一个图片给服务器,就是一点通过TCP传都能成功。为什么?因为它底层是。字节的形式,你图片视频我都可以搞定,只是大小的问题了,好,第一步先拿到长度,第二步他拿到这个长度过后,他根据这个长度来接收你的内容,因为他们两个这个链接是没有断掉的,所以它根据这个长度。
19:03
根据接收。接收到的这个长度,比如是嫩吧。就是长度。长度,比如说这个嫩来进行再次接收,再接收,接收这个消息本身。如果消息本身,如果他发现这个长度,就说他接收到的长度和这就是说他接收这个,你给我发过来,这个长度的大小和我实际接受的程度不一致,就说明。就说明有丢包现象,这个网络有丢包现象,他就会,如果要做的更严谨一点,他就会发一个消息说对不起,请你重发。啊,这个就更复杂了,就是说像一些稳定的,像像这个迅雷,像百度,它这个其实挺挺不好做的,就是要保证每次你看有时候你看为什么你中断了,你看有一条断点续续传,大家都知道断点居然你今天没有下完,你下没下完,你把这个一关闭,你第二天再一点继续接着做,它还能把这个文件进下载下来。
20:05
其实挺不容易,因为他要进入,你现在传到哪个地方去了,好那这个呢,我们先待会再说啊D,他拿到这个过后呢,他根据根据啊,根据这写错了。根据接收长度,接收这个消息本身,那接收的时候,他一定要判断,接收时,接收时要判断,要判断那个就是这个接受到这个程度。叫这个长这个棱。就说这个我实际实际接收到的实际。实实际。接收到的,接收到的这个这个这个这个消息这个内容是否是否等于等于这个呢。等于啊,等于这个人。当然如果是如果不等于这个人说明你这有丢包了啊,丢包你怎么去处理的,下午丢包处理很麻烦,就假设我丢包了,那么只有两种情况,要你代码写错了,就是代码本身有问题,再有一个就是网络错误,那网络错误的话,一般会给这边,如果他他互相有一种底层的一种协议,再叫做什么协议呢?叫做纠错协议。
21:17
他会告诉你对不起,你这个要么等一段时间再给我发这个,还有一个延时,他可能认为这段时间网络有网络,网络这个冲突,或者是网络这个到了一个网络洪峰,就是网络很网络这个很阻塞嘛,很阻塞,因为TCP有一个最经典的一个协议叫热土豆原理,你们有时候去看一下,它这个底层叫热土豆,热土豆就说它是经过了多少个路由,比如说我有一个包要发给张三,如果我经过了多少个路由,多少个路由忘了,大概是20个还是30个,我忘了啊,有个数,如果经过这么多路由,这个数据还不能达到对方。那么TCP整个这个网络,大的网络就会把这个把这个包扔掉。16个字吗?
22:00
对,反正有这么一个东西,就是说他如果你不丢的话,整个这个网络就会游荡很多什么数据呢,孤魂野鬼。就好像有一个人一样,没人管了。他认为不可达,如果你不扔掉的话,会出现什么情况,整个这个整个很多就是没有没有没已经没有主人的这个数据,它整个就阻阻塞在这个公网上面去,这很可怕,你现在知道为什么,为什么咱们这个,呃,这个公路上的一些阿姨他们扫地吧。因为那些垃圾你不清的话,你自己都出不去啊,以前我们小时候还学过一篇文章嘛,说美国还是哪个国家,说因为不满意,说我们是清洁工人,为什么工资这么低,我们全部都扫地了,结果过了几天大街上全是垃圾,你知道吗?说大致就这个意思,就数据一定要丢掉,那么这个地方呢,我们先不说那么多,就说接收时要判断这个数据是否相等,如果不相等,有个有个纠纠错协议。如果不相等,不相等就有这个纠错协议啊。
23:03
纠错协议这个就很复杂了,这个纠错协议呢,我今天就没有机会讲了,我我们就认为大不了最做的最好一点就是你过过上过上一秒钟,过上这个30秒再给我发。这个是可以做到的。就是相当于我认为现在可能是网络上比较堵塞,你不是因为我们程序的问题,就是太堵了,你达不到我的啊,这个就说行,我们这个后后面再再说啊,这个后面再说,后面说。好,拿到这个地方还没完哦,步骤还有很多,你拿到这个消息过后呢,你第五步该做什么事情呢?第五步就是你要把这个消息先把它先把它反,先把它这个序列化成这个message,就先把它序列化成这个message,然后再取出一个data再序列化,就相当于说取到这个东西过后,取到后。渠道后就可以把它序列化成哦,反序列化啊。
24:02
反序列化。反序列,哎,反序序列化,反序列化什什么类型呢?反序列化成这种MC。所以他们这两个message定义呢,一定要相同,就是客户端和服务器端的这个message的这个结构要相同,然后第六步,第六步呢,你再取出这里面的data。再取出这个message里面的data。这个大家取出来,这个时候其实是字符串。因为你你现在是相当于这这个message包裹了,里面这个message它是一个包裹关系数包含关系,然后你拿到这个物呢,你还要再返学的话。反序列化。在反序列化过后呢,同学们,这个时候你就终于拿到了。这个玩意儿。好,拿到这个玩意儿过后呢,好第七步你就可以干事,因为这里面呢,就真正能够取出他的ID和密码了。
25:03
他就可以这样就取出,取出这个它的这个logging message的message的这个user ID啊user ID和什么呢?和他的这个user message,呃,User p WD和这个logging的user message。好点user pw好拿到这个东西过后呢,非常好了,因为你有这个东西,你就可以到数据库或者到这个文件里面去比对,这时这时就可以比对了。这时就可以比较。比较比较过后呢,根据结果你又要开始给他回一个这个卖神经。那回收的时候呢,这里面又要定一个协议,就是说你可能是另外一个叫logging result message里面的内容肯定跟他不一样,你可能返回是一个错误的扣的那个编号。还有消息内容。这时就可以比较,根据比较结果,根据比较结果结果返回这个message,那这个时候message呢,我认为啊,可能长得是这样子的,待会我们在实现,同学们不着急啊,这个东西呢,为什么我说说慢一点,就是因为它里面这个步骤。
26:18
太多了。好。那到时间我返回的肯定就是什么呢?我返回这个消息类型和这个和你发送的消息类型可能就不一样了,因为我们两个是不同类型的东西,比如说我可能返回的是logging results,就是你登录的时候我给你返回消息,但是这个消息呢,可能我就定的比较简单,我可能定的是这样一个东西,比如有个code。扣一个int,这个代表你的错误码,你看为什么你有学的同学学过HD协议,你看它有200,它有500,它有404,它有403,其实大致也是这样协定的,那这个呢,你可以根据这个它实际的情况,比如说200我们就代表成功了,比如说500我们就代表,诶你的用户我检查了,哎,这个用户不存在。
27:06
对吧,好,然后呢,这边可能还有一个说明。比如说你这边有一个error error的一个信息啊,是个字串,如果没有错误的话呢,你就不用去读,如果有错误,把这个错误信息也给他打回去,所以说在这呢,我又组装了一个这样的东西,把消息类型给到他。给到他再把我这边组织的一个什么呢,组织的一个这个那塞到他的这个data。但是这地方又要经过一一系列的这个操作了,就是说你先把结构一做出来,然后传给他再序列化,呃,先把它序列化给到data,再把这个message再序列化,调到一个组串,最后把它发回去。发送给发送给客户端。客户端。那么客户端拿到这个东西呢,他又要开始对他进行刚才这个一个操作。你看多复杂。说老师这个别写了,我已经开始蒙圈了,其实我说的一个过程很复杂,但是代码呢,我一写你发现其实还真的有点复杂啊,还真的有点杂,那你写代码也是一样的,但是有一个好处就是你学完了过后,你对网络它的一个过程呢,确实是理解的比较透了,就是感觉哦,原来是这么回事,先发一个长度,再接受内容怎么怎样,为什么要发长度呢?诶老师说了就是因为怕丢包。
28:23
因为它相当于有个机制,如果你那有些同学说老师,那为什么他要是他不能够把这个长度封中到这个Mac里面一起给吗。其实这个也可以。这个也可以,这样的话呢,也是有可以可以的,比如像那个HTP协议,他在发的时候直接把这个长度给了。那是因为那是因为那个AP协议,它一连接码就断掉,我们这个TCP呢,它本身是长连接,所以说我们也可以先发长度再接收也没问题,当然有些人老师我想这样做。你把这稍微给我扩一下,说老师除了这个之外呢,我们再加一个给他增加一个叫做length。
29:04
也可以。认,那么这个认子呢,就叫就是个U,比如说一般是u in32这么表示大,就说我在这个时候不像你那样子,我先把整个这个长度都计算出来,放到这里面去,把这个包给他,然后呢,你再去读,看看这个是这套是不是等于长度也可以。啊也可以,那么我采用的是这种方式,稍微麻,这种方式呢,更稳稳定一点,更稳定一点,好这样子啊,我的思路已经说完了。就说我现在已经把我想做的这个事儿。已经跟他描述清楚了。好,那这里面就是怎么样一步一步把它实现了,好这里面还有就怎么开写生做,这只是一个数据接收的流程啊呃,发送有大概五个步骤,接收有四个步骤,当然到时候我们发送和接收呢,肯定要分装成函数。肯定要分段函数,好思路说完了啊,好思路说完了,现在呢,老师把这个思路先放到这儿,因为后面还有思路,好思路分析完毕,我们先截取一个视频给大家聊到这个地方。
我来说两句