00:00
好大家好,我们接着呢,在上面的基础上继续往下面讲解,那刚才这个代码呢,可以稍微的再修改修改哈,哪里可以修改一下呢?就是服务器这一块,服务器这块呢,首先第一个第一个就这个地方这个make呢,诶咱们可以把它提到上面去,好提到上面去。啊,因为这个地方有一个这个版本缓冲就可以了啊,如果说这对他来说只要有一个就可以了,第二个呢,呃,就是这个N的判断呢,意义也不是特别大,可以把它去掉啊,因为它你指定读这么四个字节嘛,对吧,那就读四个字节,其实这个地方呢,也还是也不是说完完完全没有这个意义,就是它这个read的含义是什么,我可以再来看一下。啊,我们再来看一下。这个connect它有个read啊,它有个read。在哪里net net net呢?有一个类型叫connect。
01:01
Connect。在。在下边儿,诶,在下边儿诶。怎么还没找到呢?Connect。我要找一下。我要找一下啊。在这个位置还没找到,往下往下往下。一上哪去,这这随便找一个吧。啊collect,那么这个collect read它什么意思呢?Read这个N啊,这个n read read的方法可能会在超过某个固定时间延时,它这个N值,N值这个地方它应该是指的它到底是读了,实际上读了多少个字节啊,实际上读了多少个字节,说这方呢,也是房子这边你虽然是写了四个,但是他读了四个没有,这个也不不清楚啊,这个也不清楚,说这个N呢,你家这也可以,但是但是因为那边指定读了四个,你不判断问题也不是很大啊,也不是很大,就判断一个error也可以了,这样也行。
02:06
好,那下面我们接着来看了,下面呢,我们这做了一个修改过后呢,我们接着来完成下一个功能。那下一个功能是什么呢?同学们看到下一个功能是这样子的,完成客户端可以发送消息,本身服务器可以接收到正常的消息,看起来这么一个小小的功能啊消息,然后呢,判断这个用户到底是应该呃登录还是不应该登录了,把这个呢,咱们就一并完成了啊一并完成。好,我们来完成这个代码了,完这个代码,我看这方还有一个好,那现在就来开始玩玩这个东西啊,到底有没有成功。到底有没有成功把这个功能实现?就是完成客户端可以发送消息,本身服务器可以正常消息。消息并。并。并根据根据根据这个客户端发送的发送的这个消息,这消息,但是这个消息呢,目前呃,前面老师已经讲了,其实它是一个logging。
03:13
Logging message,根据这个消息呢,诶,根据这个消息我们来判断到底是一个合法用户还是一个非法用户,判断判断用户的合法性,判断用户的合法性。合法性并。并返回相应的这个消息,并返回。并返回相应的相应相应的啊,相应的这个logging。Response response这个这这个这个内容。它看起来挺简单啊,但是呢,因为这是第一次写这个结构,所以说它的工作量呢也不小,所以说呢,我们还是来做一个思路的分析。
04:05
好,功能要完成什么,大家都很清楚了,现在我们来看思路分析。那么怎么来完成这个东西呢?怎么来完成这个东西呢?我觉得步骤呢,应该有这么几点啊,同学们注意听。呃,首先第一个。你你首先第一个先。让这个客户端发送消息,本身这个肯定要有的,让。客户端发送。消息。消息本身就是客户端发生的这个消息,就是它那个登录消息这第一步,第二步服务器端。要把这个消息。收到,然后将其反序列化成对应的这个message啊,然后服务器端。服务器端接收到。接收到这个消息。
05:01
你,你接收消息此时此刻,说白了它是一个字节,字节束,字节切片,你接到消息过后,要把它反序化,然后反序列化。反序列化成什么呢?要把它反序列化成,呃,这个对应的对应的消息结构体。结构体。第三步,根据这个收到的消息内容。返回响应的消息。服务器端啊,服务器端,服务器端根据根据这个反序列化的这个消息。判断。判断是否是一个合法的用户,判断是否登录用户,登录用户。是否登录用户是合法的用户?是合法的用户。
06:02
判断判断过后呢,返回。半回。返回什么呢?返回这个logging。Logging response message。但你返回的时候呢,也要做虚拟化的工作,最后客户端根据接收到消息显示对应的页面。最后客户端。客户端。要又又又要解析它,又要解析这个返回的,返回的这个log。Logging这个response message对吧,然后呢,显显示啊,显示对应的这个页面。对应的这个这个界面。大致就分这么补啊,看起来好像挺简单,但是呢,仔细一写,代码量其实也不少,代码量也不少,那么我们一步一步的来完成,其实就是发送处理。
07:04
返回再处理。那这个时候呢,我们可能要涉及到一些函数的封装。这里面我们要做一些函数的封装。这里。我们需要,需要。需要干什么呢?需要做一些函数的封装,需要做。函数的封装。OK,好,下面输入有了代码实现。代码实现。那,那就一步一步的走吧。一步一步的走好,先来把第一步搞定吧。打开我们的Vs code,找到。我们这一个log紧,那你这个地方已经把这个长度发过去了。我们那边呢,也顺利的接收到了,现在呢,我们不着急退出,现在接着发送。发送什么呢?发送消息本身。
08:00
那么你发送消息本身其实也非常的简单。也非常的简单,你不是有一个collect right这个连接吗?那其实就跟这个思路是一样的了。把这个粘贴复制一份。把这个复制粘贴,复制一份粘到这里来。好怎么做呢,这个地方我们要发送的内容。大家都非常的清楚。就是对。就是,呃,就因为你已经把这个message已经序列化成了一个data。说说你这发的就是一个data。好放放进去,那放进去过后呢,嗯,这边就是看看它有没有发送成功,但这个N,这个N呢,意义也不是特别大啊,我们主要是判断,我们主要是判断它这个有没有产生一个L。好,这边如果A不等于near,那就说明这边发送又失败了啊,发送这个data失败。
09:02
就你没没发出去,或者是什么原因。好,这个就发出去了,就是发送消息本身。好消息本身过后,这边你待会还要涉及到一个接收的问题啊,待会再说接收这里还有一个新的问题,这里呢。这里还需要。还,还需要处理。处理用户就是服务器端,服务器端返回的返回这个消息。还得一一步一步来啊,还得一步一步来,那你这边把这个data传递过后呢,显然我们这边我们这边这个携程呢,要去读取,那读取怎么读取呢。那就写server的meeting go还要在这写,但是大家想一想哈,如果我们在这个地方写。显然有点。不划算,因为你这个在在这个在读的时候,你就是在读,在这读完这个地方呢,你要读它这个内容的话。
10:10
嗯,最终呢,我们希望读完这个数据就过后,就直接给我们返回了一个什么呢,消息体。就是它有个它这个读,读的事情很多,它不仅简简单单就是把这个字符串读到它,还要把它重新恢复成一个结构体,所以说干脆我们就封装成。封装成一个函数啊,封装成一个函数应该更合理一点,所以干脆呢,我们就这样做啊,大家看我这里的思路也是这样子的,怎么做呢?咱们这个地方把它写成一个package read package,大家看大体的意思是这样子的。大家看这里啊,你给我一个链接。你给我一个链接,然后呢,我返回给,最终我给你返回一个什么呢?啊,给给我read啊,你给我一个链接。
11:02
啊,给我一个链接,然后呢,我读看到没有这个长度,长度读完了过后,我直接序列化,把这个message给你序列化给你返回去。就完事了,如果有错误呢,我还给你返回一个错误啊,给你返回错误,同时给你返回一个message,就是我把这个message就给你直接封好了,整个我就给你封好了,是这么一个逻辑。大家看我的思路啊。因为这个你你在这样读数据,你最终不就是想要一个读完过后拿到一个message的这个,呃,Message一个这个结构体吗?对吧,那这样子就简单了嘛,这样就简单了,所以说我的思路呢,就要做这么一个封装的工作,跟上老师思路啊,现在我们来开始封装。那干脆把整个这个地方代码封装起来,封装起来它就是可以循环的读啊,循环读,所以说我在这里做一个工作。这里我们我们将将读取读取这个读取这个消息,读取数据包吧,叫数据包直接。
12:10
直接封装成,直接封装成一个函数,那么这个函数的名字呢?咱们就叫read。Read这个PKG。那么这个read完了过后呢,这个你首先肯定要给我连接,给我一个链接,我返回给你一个什么呢?返回这个一个message。我给你一个message和一个error,如果有错误就是error,好,现在我开始封装了,那下面这些代码呢,我都要有可能要把它拿走了啊。那我整体把它拿走,这样拿走啊,大家看从这开始。整个。整个我复制一下。捡走先先捡走啊,先捡走,那么这这个地方我就封装了一个函数,注意听啊,Package package,嗯,然后呢,Read这个p kg package,然后里面你给我一个连接。
13:09
你给我一个连接,那连接是ne.connect。Net,最后我给你返回的是一个message。我给你返回,这样写吧,Message,然后呢,Me,呃,这个包包里面的。第2M1这个类型,同时呢,也有可能有个L。好,把A也给你返回,好,就这么一个玩意儿。那么你你这么一个东西呢,前面那段代码咱是大致相同的。前面那个代码呢,是大致相同的,所以说你看这个地方我开多少个空间,对吧,还是开多少开多少空间,还是读这个长度,读完过后下面这个步骤。下一组就根据。不听。根据什么呢?根据我读到的这个长度,就是8UFF本啊八本这个长度转换。
14:06
转成一个什么呢?转成一个UINT32的这个类型。我要这个,为什么要转呢?因为我想知道,到底我应该读多少个字节。我到底要多读多少个字节,所以到这个地方呢,我们要做一个转换。要做一个转换,怎么转换VR?好,PKG。啊,PKPKG嫩先给它来一个类型,叫u in32。写完。然后怎么把一个buffer这么一个长度转成转成什么UNIT32这个呢,还得用刚才类型。用一个什么类型呢,这样的一个类型啊,Binary。点点刚才那个函数拿来用用。刚才那个函数我们是在。
15:00
捞进的时候,我们用过这么一个函数啊,它。好,不着急写到这儿来。写到这,写到这的地方怎么用呢?要把它换成一个UNIT32。UNIT032,这个时候不要写那么多了。PKG,大家看这个意思是什么意思?解释一下这个这个地方的含义啊,打开我们这个手册。但。大家可以看到在battery里面有一个这样,刚才老师写的这个函数,我们看一下是在encoding里面的这个bay,点进去大家看这里面有个offer,它里面有个这个函数叫。YOU3。You。INT32,你把这个BAT切片放进去,然后给你返回一个UT32。也就是说这个是反方向的一个转换,把BAT这个字符序列表示的一个表示一个字转成一个UNIT32,那我们就拿到了,就拿到了,好现在呢。
16:08
根据这个package认识来读取内容。好的,根据。根据什么呢?Packag读取。读取消息内容。那怎么读呢?显然很简单。点read。Read。好,Read的多少呢?八本?切片。走,我要读这么惨。注意啊。这句话怎么理解啊?这句话不是从buffber读,而是从这个connect里面读,这么多个字节扔到这个buffer里面去。有些同学把这个理解错了啊,再说一下这个函数的意思是指得从这个connect,这个套接这里面读这么多个字节,扔到这个八分里面去。
17:07
不是从这个buffer里面读,是值得我从这个看类里面读这么多个这这么多个字,衍生到这个buffer这个这个缓冲里面去,是这个意思啊。好,那么你自己实际上你读不读到这么多,你不不敢肯定。所以说刚才有同学说那个那个判断没有意义,不是这样子的啊,其实那个判断式还是有一些意义的,因为你你只你想读这么多,你就一定能读这么多吗?不一定啊,他可能你说你要读四个结果,你结果那个C连接只给你发了两个字节呢。对吧,他不一定读到那么多,他是希望读这么多,但实际从这个con读多少个字节不敢确定的,所以说这地方呢,我们写个N和L。OK。好的,那这个时候呢,我们就要做一个判断,如果这个N它不等于你实际期望读的这么长度,那就说明有可能丢包了。
18:06
这个道理和刚才那个四的比对,其实是一个意思啊,其实是一个意思,然后呢,或者这个L不等于零。就是有两种可能性,第一种可能性,我的的确确从这个C里面读到东西了,但是呢。我想读,比如说我想读20个字节,但是我实际上只读了。十个字节。那说明错了,还有一种可能性,就是因为对方管道关闭了。也有可能错误啊,所以不管是什么原因呢,都是错误,所以说我们打印出来这个错误信息叫做什么呢?Connect read l。Feel a等于轴。输出来,那么这个时候就return啊不做了,好同学们,到这个时候我们这个八本这个这个东西就是我们这个字串了。
19:01
就是你的那个消息,就是那个消息,所有这个那个字节,字节切片就过来了。但是你这个切片没有用,你还得把它转成一个真正你要的那个message。要进行反序列化。好,现在我们已经拿到这个字节了啊,注意这是字节。还得转。对,现在要给他把。把这个把这个package反序列化。就是它是个反序列化。存。成什么呢?成哪个类型呢?先把它把序列化成这个类型。因为你现在发的时候是以这个message类型进行序列化的,所以说你在反序列化的时候呢,你也只能先把它反序列化成message这个类型,然后你把这个里面的data取出来,然后再去反虚化成,反虚化成这个这个log message啊,它是一步一步来的,所以说这有点复杂。
20:02
其实也不是复杂,就是步骤呢,要多一步,这地方容易晕,好一步步来吧,先把它反修成这个类型啊,注意听我稍微慢一点。点。这个类型,那你既然要反句话,你你怎么样反虚话呀,你首先得声明一个这样的变量才行,对不对,所以说呢,你VR你先VR一下message。然后呢,Message me。那这个时候呢,它其实是个空的啥都没有,诶这个没有必要,是不是上面已经有一个这个了,说这地方没有必要再再再去搞这个玩意儿了,因为它这个参数已经给给你传了一个过来,那我直接用它就可以了,是不是啊,那直接用它就可,因为它这这个这个返回值已经相当于说给你给你生命的一个,那那我就简单了,那我怎么做呢。接点on muscle。
21:00
怎么做?嗯,第一个参数大家记得填什么东西吧,第一个参数填的就应该是。这个字节切片第二个参数就应该填这个准备返回的这个名字,但是呢,各位同学一定要注意一个特别重要的细节,要把艾德加上,如果不加这个艾德补后果是什么,你知道吗?Message是个空的。这个地方我是吃了大亏的啊,但有可能你你不一定调的出来,因为我们这样很很容易忽略这个问题,这又是一个坑。但这个坑其实按理说让你去踩一踩。说这个咱们为什么说有时候呃给你们讲这个东西呢,就感觉好像没有什么错误,但是都给你说出来了,其实这地方是特别特别重要,我可以先告诉你们啊,如果你这没有没有加这个艾特符号,你将来从这地方拿这个messages的,它是个空的,就根本就没有真正把这个虚这个数据扔到这个message里面去。
22:02
好,这个地方是特别重要一个细节,那我你看为什么我在这地方加了一个标红的位置。就说明我曾经踩过这个坑啊,当有人说这很正常吗?是人家说出来过后,肯定你觉得是很正常的,但没说出来的时候呢,你你觉得正常吗?你想不到哪去,所以说我们经常说一句话,说什么呢?就说技术啊,记住这句话,技术就是一层一层什么呢?窗户纸。啊,就是一层窗户纸。窗户纸知道什么意思吧?就说把这个窗户纸捅破了,你看到你觉得是啥都没有啊,这个好简单嘛,但是不捅破这个窗户纸呢,你永远觉得这个很神秘。所以有时候你看,呃,有时候你去问一下别人说,诶你说这个东西怎么解决啊,可能这个高手或者有经验的人做过,这人说好,那地方你要小心,这一点就过去了,但是他不不给你说这个。
23:00
你真真不知道啊,你真不知道,所以说技术就是一层窗户纸,这个是谁说的这句话呢?我们以前那个,呃,就韩老师刚刚参加工作的时候,我们那个CTO他说的,他说我也是这样,就是说了就知道,不说你永远不知道,就这么简单一个东西,对吧,就好像你你去炒股股票,那人家告诉你,诶那个股票有一个A股,有一个什么什么什么一个铝财要生了,就一句话的事。不告诉你呢,也不知道啊,好了,这个地方一定要重视啊,这方一定是爱的符号,爱的麦,注意。好了,这段序列化过后呢,会返回一个什么呀,应该是返回一个L,那如果说你失败了,那你就要做一个判断,就说反序列化失败。对不对,那你打印出一句话吗?P。好,不着急啊,这边还有好多东西要做呢。说写写个代码还挺累的。这个不但要动脑筋,体力上也是个消耗啊。
24:03
啊,L。对于。哎。好,当然这方需返修了,都不成功,我也不玩了。我也不玩了,那就把这个A也就也就返回去了嘛,相当于好,那你做完这个工作过后,其实你这个地方已经被学的化成功了,好学的很多,最后最后地方还应该有个return,因为他担心你不进来,好最后就这样子的啊,最后11返回的是一个message。和一个L,那如果没有L没有进来过呢,这个里面L是个零,对不对,是个零,好,同学们,这个就写完了。这个就写写完了,那么这个写完的原因,它为什么报错呢?因为我们没有相应的包包,Go cold对不对,然后呢,Chart room。Room斜杠,然后呢,我们写的这个叫common,下面有个message包包。保存一下。好,还有错误。
25:01
No new,他说这个地方已经有了,因为你这有个相当于说这个返回是命名嘛,所以说你这呢,就不需要再写这个东西了。好的。还有一个这个包袱没引进来,那就是coding,对不对,我为什么要给他写一遍啊coding。And。呃,这样n coding coding这样写的吧。B。啊,多了一个一,多了一个一,嗯,Cody啊好。好,这个地方就应该还有一个什么玩意错误,看看无效的类型,对这个地方呢,有一个问题,因为你这个N是int,而它是一个这个UU,那个in in in32,那把它转一下就行了。对,把它转一下就行了。好,这地方还好写写错了啊,不能这样转啊,这样转。降准。
26:00
好,还有哪地方看一下。这还有一个,嗯,他说这个接上这个包没有引进去。好,我们把这个接绳包也引进去,完事。好,这个经经过一番这个痛苦的挣扎,我们把这个写完了,那写完过后呢,现在就变得简单了。OK,那这个时候呢,我们相当于说就可以拿到这个内容了啊,那么写一下写一下,那怎么写这个东西呢?好,你read不是已经拿到了吗?那就是调它一下就可以了,Read。好,首先我揭揭一下。这边有一个A。接收好,然后呢,第read package,我把这个con传进去。C传进去,好,那这个时候这个message呢,我们就应该拿到啊,Message就应该拿到,那么我们判断一下,如果L不等于零。说明我们这个读取就成功,呃,失败了啊失败了,那打印出一句话就说这个read package出错了。
27:06
Read package输错了,错误的原因呢,也可以把它打一下。啊,打一下这个地方,我们最好这样做。呃,有些人喜欢这样子,这个头如果出错了啊,就是这个地方是头出错,他一般会返回一个自定义的L,也有也有这种写法,他不会这样做的,比如说这个是。出读了个头出错了,这个是读我们的内容出错了,那么一般可以自定义一下啊,自定义怎么写呢?就是L这样写。A等于呃,As l,我们以前讲过这个a.as点661个A。是这样写的吧,又一个L。啊,看一下这个A里面应该有个六,我记得啊,就是一个直接是个六吗?点一下。好是不是,诶对,找到就是一个六啊,没有后面没有东西直接是个六,六一个什么呢,比如说我们写一个叫做read read什么呢,这个package的hi l。
28:11
他投诉错了。啊,投诉错了,好这样子呢,嗯,可以就这句话,我们就不要啊,不需要把这个创建一下,给他一个负一个值让他返回,那如果说下面这个啊,下面这个呃,Read它的这个body体出错了呢,我们也可以这样子给它定义一个自定义一个错误,那就read package的body error啊,这样大家就更清晰了,那上面呢,我引入这个L方。好,这样子就OK。好,这边还有错误是吧。看哪里出错了,这有个错,定下位。好这里吗?啊,这打了一个空格,好这就写写完了,那根据错误信息,我把错误信息读出来。他的message,呃,用了,但是没有没有使用,那么我们把它输出来,看看消息是什么message。
29:03
啊,Print。Message等于啊,我们把这消息呢,给它输出来啊输出来,嗯,因为现在接收到的这应该是一个就是具体的一个消息了,对吧,具体提起一个消息,我可以把它输出来看一下。好,A呢,可以。好,这个呢,我们就是到哪一步了啊,现在呢,我们已经可以接收到这个正常的消息了,就把消息接收到,但是你这个消息接收到,你还没有去处理,还很麻烦,还要写。那么我们先测一下啊,同学们,我们先看看这个消息有没有得到,就是我现在先测一下瑞的派克到底对不对,因为这下面还有一系列的逻辑,就说你拿到这个消息,你还去判断到底怎么怎么做,怎么怎么做,又是一堆代码,好,我们先测一下,同学们,好朋友们,我们先来玩一把,看看对不对呢?啊对不对呢?好,来一个。先编译一下。
30:01
因为客户端好像我们没有变化,哎,客户端好像也变化了。客端也变化了,没有毛病。再来看我们的服务器端。再来看我们的服务器端啊。大家明显感觉到现在有有点逻辑上有点儿多了哈,明显感觉到有点多了。那这个很正常很正常,编译也没有毛病,先启动我们的服务器端。好服务器端,然后呢,启动我们的客户端。好的,大家看它等待空上的连接走一个一。我们现在看看我输的这个ID号,还有密码,他有没有真正的拿到。100密码呢,来一个汤姆啊,来个AB CAC,呃,OK。灰色。好,同学们可以看到现在呢,这地方有一个问题大家看。他读这个头啊,读这个头一直是没读到的,他说读取客户端发送的这个数据。
31:04
但是这边发送的内容呢,应该是正确的啊,现他说读取这个客端发送去发送数据,这是卡顿,我们再看看哪里出错了,说read PI hier error哪里出错了呢。找一下read,呃,定到这个函数里边去。他是read是内出错了是吧。到那个。我这这地方没有退出吧,按理说。对吧,哎,我们刚才那个头还读到了吧,我记得为什么现在写到这里面就读不到了呢。为什么这个就没读到呢?他现在报的错误,先看看是什么。来看一下。
我来说两句