00:00
好,各位同学,那么我们接着上午的内容呢,继续给大家来进行讲解,上午哈,就是前面呢,我们给同学们就是说了一下,我们这一个就是关于我们这个TCP通讯的这么一个基本的一个步骤,那这个步骤呢,它相对来说步骤看起来是比较复杂一点,但是代码呢,呃,都要,但是代码也还是要体现好,要体现,所以说我们一步一步来看,那么怎么样做呢?来我现在这样说啊,我们先把刚才的message的组成,还有发送一个message的流程给大家做了一个介绍,好,我们先把这个板输一下啊,先把这个板输一下,然后呢,我们就用代码实现它。OK,这个是实现,诶OK实现,呃,就说完成这个用户登录,对完成这个用户登录,给他来个标题三,那么我们刚才呢,呃,就是说了一下完成这个登录的要求,我们这个要求是什么。对这个要求呢,同学们可以看到哈,我们这个要求呢,就是要实现,当用户ID等于100,密码为1234的一二三四五六十就可以登录其他用户,暂不能登录指定用户。
01:14
第二个呢,我们在这个基础上,我们做了第一步,就是在这个地方说了一下message的一个组成示意图,还有呢,就是把它的一个流程,就发送一个message流程,我们给大家做了一个介绍,那么怎么做的呢?诶我们是画了一个示意图,这个示意图呢。已经在这里了,我先把它拿过来。后面还要在这个图上进行进行更新和相应的改进。好,我把它也放在我们的笔记中去。啊,那下面呢,我们就来针对这个message呢,呃呃,做一个实现功能,先实现哪一个功能看啊第一个功能。在这个就说完成用户登录的这个基础上,先完成他的第一第一部分哪一部分看这里。
02:05
就这一个功能,咱们就得讲一会儿啊,因为前面是最费劲的,前面是最费劲的,完成客户端可以发送消息的长度。消息的长度,服务器可以正常的收到该长度值。什么意思?就是我们先完成这一条线。完成这一条线,把这条线它发过去的长度先接收到,就服务器这边先能接收到,把这一步先完成好,我们来把它做做一下啊,做一下思路。具体来说我的这个分析一下这个思路。我的思路是这样子的。同学们,第一步。第一步,首先我们先要定在代码上,先把这些消息的格式定好,先定。先确定,确定消息,也就是message message的这个格式。
03:06
和它的结构。和结构啊,这是第一步结构啊结构。第二步我们让哪里呢?我们让这个服务器这边来进行监听,也就待会儿呢,它这个代码是这样,这个是分析图啊,待会儿呢,是这边这边会有一个服务器。服务器在这里进行一个监听。这是我们服务器代码,服务器代码呢,目前我们也到时候也写一个main点购。没点go就是服务器啊。啊,当然要加东西了啊,服务器,服务器在这里监听。他在哪里监听,他在这这有个这有个端口。这个端口呢,我们把它定成8889,但你也可以随意。这有个端口监听。好,这个端口呢,我们把它定成8889在这监听啊,那客户端来了过后呢,我们怎么做,假设这边有一个客户端来了。
04:08
OK。好,这边这边客户端呢,我们把它假设是A客户端。A,客户端的它的代码呢?呃,目前有个main.go然后在这里面我们还要增加几个文件,增加一个什么呢?就是呃loging.go好像也有了logging点购,我们再增加一个u tr.go这个文件啊同学们。这个U点构呢,是我们的一个工具,就是关于发送,发送这个消息包和接收消息包呢,我们到时间都在这个地方写东西,就是u tears里面呢,封装了我们相应的一些工具,好这时呢,我们要这样做,它连上过后他先跟他。进行一个数据的请求啊,就是连接连接完了这边呢,这边主程序它是在这监听的啊,你可以认为这是它的一个主,呃,主线程主线程。
05:01
这个没问题,主线层,那么主线层呢,它这边会有一个呃,上下文空间对不对,有有个空间上下文。假设这个呢是个P。啊,这边是P,如果说来了过后呢,我就起一个携程跟它对应。这是P。当有一个请求过来以后,就这边来了一个请求过,过来以后呢,我给他开一个携程。就这个携程呢,是专门让他跟客户端进行这个交互的。啊,这边有一个斜程。好,我换一个别的颜色啊,换一个别的颜色,比如说这个这个颜色吧。好,这边起个斜程。好,直接写就行了。携程。那这个这个携程呢,呃,就跟我们的这个客户端,这个端口它是有关系的,就相当于是这边这边他们联系,然后呢,通过这个端口进行这个相互的通讯,相互通讯,好现在呢,我们来把这个思路说完了,我们来开始写代码。
06:11
好,写代码的时候先把哪一个写出来呢?大家共用的一个部分,因为你将来这个客户端还有服务器端啊,这边假如还有一个客户端,他们都会要共用到一个消息结构,对,他们都要用到一个消息结构假设,嗯,因为服务器这边呢,他也要去读消息,而你客户端呢要发消息,反过来也是一样,服务器也可能发消息,客户端呢要接收消息,因此呢,我们新建一个包包。Package这个包P,哦,Common这个包里面呢,我们建我们的消息结构体。叫消息。消息的这个这个这个结构。好了,现在思路都有了啊,我们现在开始走,先先写它。好,首先我们新建两个文件夹,第一个是a common。
07:05
嗯,这个server已经有了,看下面呢,我们再建一层文件夹,专门发布消息,如果以后呢,呃,还有新的共用的部分,我们就也写到这里,Server这边呢,至少目前呢,应该有一个文件main.go这是必须有的,对吧?main.go。没点go。好,这是至少目前需要这么一个东西,好,现在呢,我们来开始先定message。PA,这代码稍微有点有点长啊,这边这是消息,我们有一个import。这边可能不需要import直接定东西了,嗯,Type。Type message。它是一个结构体。结构体呢,根据我们上午的分析,他目前需要有两个字段,一个是type,一个是data,就是它的数据,这个数据呢,到时是具体的某一个具体的消息类型。
08:09
OK。好,现在呢,我先确定它type。现在我先都不仅封装,我都把它做成一个公开可以访问的十寸。这个是消息的类型。OK,那么data这个呢,是消息的内容。消息的内容。注意啊,这个地方不要把它字定义成这个,呃,字节字节切片,因为你到最终在操作的时候,在程序里面操作的时候,它仍是字符串,好我们现在先定我们目前需要的两个具体的消息。啊,具体的具体的消息啊,先确定先定义。好,先定义。先定义。定义两两个消息,那后面还可以增加啊,后面再增加。
09:03
后面需要的再增加,需要再增加。呃,目前我们需要至少需要两两种具体的消息了,一个呢就是登录的这个消息,第二个呢,就是这边回送的有个登录的结果消息,这是目前两个马上就需要的,先把它写起来,其他同学们可以在基础上很快就扩展type来吧,Logging。Message这个是我登录的一个消息,当然都是结构体啊,你既然是面向对象,你这个TCP也用用到面向对象嘛,你肯定是定成这个结构体的,那它里面有哪些信息呢?第一个各位朋友,第一个URID肯定是跑不了的,因为你在传递的时候,你没没有UID肯定跑不起来嘛,你登录肯定要给他,所以说是个特类型,这个是用户的怎么样ID,第二个。用户的什么呀,用户的密码跑不了,你用户的密码跑不了,给他一个吧,使尊。
10:00
这个是用户的密码,那后面呢,有可能还需要传递一些其他信息,比如说user内蒙。Username。好,我也先写到这儿,用不上也无所谓啊,后面再说用不上我们到时间呃,扩展的时候还能用到用户命名,用户名,好这个就写完了,这是一个紧接着呢,我们还需要还需要一个logging,就是他这个登录过后,我这边给他回送的一个消息,这两个消息长得不一样。这两个消息长得不一样,看刚才我说的它有个code code就是它的,它是它的一个代码,嗯,代码值啊,或者叫返回值,这边error呢,是它错误的描述,OK,好,现在呢,我也把它定起来。来了啊。好,那么第一个cold。Code ID,这个是用来描述返回的一个一,一个一个代号或者一个具体的值,就像我们,呃,像状态码吧,如果同学们学过HDBHDB的话,就知道有个状态码,比如说400呀,500呀,404啊,比说403啊等等等等,那么这个就是我们返回的一个状态码。
11:17
返回状态嘛。那么多代码呢,我们先确定两样,500表示该用户还没有注册,500表示该用户,该用户未注册,未注册就是说有可能你查的时候,诶,你给我来一个ID,我发现没有这个人。没有这个ID,那说明还没注册,还有呢,我们目前在确定一个200 200表示,呃,登录成功表示登录成功。登录成功成功,当然你可能还有别的,比如说你用一个300表示什么什么你的权限不够啊,诶或者是网络不通啊等等等等,好后面可以再说,另外呢,有个L,这个L呢,用时准表示,就说你这个错误信息是什么?就是返回的一个错误信息,如果没有错误,就是一个念啊,就是返回的。
12:06
返回这个错误信息,返回错误。错误信息,OK,好,这几个就弄好了,再来一个同学们。大家看到这个type。这个type你最好给他一个常量来确定,就说你现在看啊,我们这个logging message,还有logging response message呢,将来都是填充到data这个地方,那这个地方你给他什么呢。你得给他描述你这个消息是什么类型,其实就是这两个类型,但是这个是结构体本身的名字,消息呢,你还得给他一个字。大家看看能不能理解的意思啊,这个是结构体的名称,但消息呢?你还得给他一个字符串呢。所以说呢,这个消息呢,我们应该定一些常量啊,确定一些消息类型。
13:02
确定一些,呃,我就直接写,大家看能不能看懂啊。抛起来。大家看一下啊,那我现在定义这么几个,第一个呢,我们就叫这个类型。他呢,给他一个值。等于等于什么呢?哎,我们就把它叫做log级message,就是将来我给它一个这样的,因为它就个字符串常量嘛,这样肯定管好管理,你不能说每次就在这去一个个给太累了,所以说消息类型呢,我们都定义成常量,他不能改,同样还有一个消息类型。还有一个消息类型呢,就是这个返回消息,就是登录返回的消息类型,这个呢,我也给他一个一个字符串,这样大家都知道哦,只要一看这个就代表什么类型。同样,我就省事把它写进去。好,这是消息,咱们就定完了,大家看一下。
14:02
啊,在这个后面我们还要加很多消息啊,比如说将来还有这个用户上线的消息,还有聊天的消息,还有等等等等什么消息,结果肯定是不一样的,好现在确确定了两个,好确定这两个过后呢,我们再继续往下走。那下一步该干什么了呢?来看,发消息。发消息,那也就是说你现在今天上来过后,你要准备下消发消息,因为你可以你可以构建一个message结构体并发送了,那现在我们的代码应该先从客户端开始写。啊,同学们,今天这个思路有稍微有点绕啊,跟上思路,同学们好,首先找到我的这个logging。看这里,现在先将其注销。开始发东西了,你发东西你都没连上,你发啥呀,是不是先得还还不能先,先发消息,你还先得先在这边一个监听,这边连接是吧,先把这个事做好,来吧,先把这个事做好,还没做这个事呢,来先做这个事情来打开这边一步步来啊,先在服务器这端进行一个监听。
15:08
诶,好。啊,刚才我把这个写到这了,这这个没关系,把它整过去就行了啊,我这写错位置了,没事,就是我重新写一下message点够。直接把它扔到这里面。啊,然后这边这边刚才写的位置不对啊就可以了,我把刚才message的定义放在这个文件里面才对,不不能放在门点勾啊,门点够那肯定是men点勾时候呢,我们server嘛,回忆一下怎么写。好,Import。好,来,同学们放主函数。首先我们要完成主就是完成我们的这个服务界面,点构在这里监听来怎么写,首先呃,先给他来个提示吧,先给提示信息。提示信息啊呃,来format点呃。
16:05
说服务器服务器。服务器在8889端口,端口监听。监听,OK,那一旦监听,那么下一个代码就应该是我们的net,回忆下net net什么样?net.listen。Sistn,没有写错吧?Lin,然后呢,写上我们是TCP这种协议,然后我要在哪里,我要在这个本地盐亭。走,然后我的端口是8889。好,这边呢,就会返回两两两个东西一个listen。还有一个就是error,如果有错误的话呢,我们就不监听了,写句话if。If好if的话呢,如果A不等于near啊,不等于near就说明这个错了。
17:00
我们就提示一句话,不玩儿了。第一句话说listen出错,Night listen出错了,L等于好的输一句话。跑路不玩了,注意,因为你监听都监听不了,那大下面代码就别要别玩了,好一旦监听成功,就应该循环的等待对客户端来进行接来来进行连接,一旦一旦监听成功。一旦监听成功,就等待,等待什么?等待客户端,客户端来连接来连接服务器,那这边应该是循环。我一直来等待你的链接,那下面代码应该怎么写呢?应该是我们的listen。第二,Apt。好,那这边一旦连接成功哈,这边就是相当于说我可以提示一句话,因为我们刚开始的时候呢,可以给点提示,就说等待。
18:03
等待客户端。客户端来连接来连接我连接服务器。OK,那这边一旦嗯,Except成功了,它应该返回一个什么呀,它返回一个连接,这个东西很重要,将来这个东西特别重要啊,这个这个东西就是将来服务器和客户端之间相互相互交交互的这么一个重要的重要的一根线,呃,准确不是两根啊,我不能这样画,这样画很容易引起大家的误会。呃,应该他们是一根互通的一一个管道,或者叫一个套节字,所以这个线呢,咱们还得画的严谨一点,诶,哎,这样画才是正确的啊同学们哎,这样画才是正确的,你不然的话,导致大家认为好像是一会去是111个一个连接,回来是一个连接,那就错了啊,那就错了,好这个线呢,你就理解成就是我们这个可爱的怎么样connect,那么这边有个错误L。
19:05
L。OK,那这个时候呢,我们来做一个判断,如果L不等于near,说明我们这呃,这个except呢,可能是出错出错了,所以说要玩一把。Listen提示他一个信息,Listen accept出错。L等于,那这个呢,地方可以暂时不退出,因为可能有一个连接出错了,其他呢还是可以工作的好,紧接着这拿到这门该干该干什么呢?各位,我拿到这个连接过后,我就应该起一个携程,让他为我服务,这个是老套路啊,同学们老套路够一个。就是一旦成功了后,就是一旦连接成功。一旦连接成功,则则启动启动一个携程和谁和客户端,客户端保持数据的数据的呃,数据的交互,或者叫通讯吧,保保持通讯。
20:10
报出通讯。保持通讯。所以说你会看到写这个网络啊,特别有意思,如果喜欢喜欢网络的同学特别喜欢写网络,他会觉得很好玩,他感觉好像有两个人在那玩一样啊,一边这边,其实我们现在网络加服务器才会真正的有价值。现在经常有一些做游戏开发的同学是吧,现我看好我以前有好多好多学生啊,用用来做游戏开发啊,勾勾浪也可以做游戏开发啊,勾浪也可做游戏开发那些人他们他们的工资都是比较高的啊,有游戏一上线啊,骗骗骗个几千万是吧,然后给你发点对不对,给你发个发个十几20万不小case吗?对不对,很好的一件事情嘛,所以说这个这个学网络加服务器,大家一定要知道,你学的东西越难才会有价值,如果天天学的东西,诶一听就懂,这东西最好别学啊,因为你你觉得简单,人家也会觉得简单,这是肯定的,而且这个东西没有瓶颈,所以为什么以前我们在以前我们做培训的时候,我是零六年做培训,那个时候说实话做做培训那些学生出来过后就就感觉很高大上,现在学生太多了,所以现在咱们必学高精尖的东西啊,好,我们接着往下走吧,Go。
21:27
Go什么呢?啊,不是这个go啊,Go process走,那现在呢,我们就写一段函数啊,这个是处理处理和客户端的通讯,对不对啊通讯。那你要通讯的话,你必须得有一个函数啊,那就process呗,最经最经典的取名就是处理。好的好的啊,大家看到你在处理这个,处理这个通讯的时候,一个最重要的东西,你必必须给我传过来。
22:03
就这玩意儿,你连接不给我,我没办法跟人家玩,就这根线,你得把套接字给到这个携程,你不给我套接字,那我就没办法跟他保持一个通讯了,就玩不动了,好所以说呢,这个地方我们一定要把套介质传给他,说这里面呢,有个CN这个套件字是引用类型,所以说你不用加那个星号了啊各位同学net.cn connect这个大家都很清楚的,好,那么这边我在传的时候呢,也要把这个connect传给他。啊,它一传过,他又去等待你的连接,好的,现在这一块就是读取啊读。读什么读客户端发送的,发送的。发送的这个信息,好,同学们看,现在呢,我们这边已经开始等待他发了,那现在代码呢,你就得回头往这边写了,因为你现在在写呢,你没办法测,没办法测,所以说现在人家已经到哪一步了,已经等待你来发东西了,而你还没连我,所以现在呢,代码又回头在客户端来写一点。
23:08
因为我们的目标,我们这一段的目标先是干什么,先要去完成可以接收消息长度,再说消息的本身好,那现在呢,来回头写客户端。因为人家已经把这些工作都做好了,等待你来年了,你还没到这来,好好,我们现在呢,在这里来玩一把。好,找到我们的客户端。我们客户端的代码呢,目前是在这儿。Go。好,那现在我们就开始在这里,你看啊,他是这样子的,他一旦进到这就准备要登录。你看它这是logging logging呢,它就要登录,它要发东西好开开始在这好可这第一步。第一步,连接到连接到服务器端。服务器好连接服务器,这个很简单,我们学过一个东西叫net拨号,对。
24:06
然后呢,我要拨到哪个地方去呢?好拨到那个,因为我这是本地,所以我写的local,好我写local cost,那实际这个情况,将来这个地方到底连哪应该去读一个配置文件,理论上说将来应该去读一个配置文件哈,呃,这样子呢,你就不用去改源代码了,所以以前我们学的那个读配置文件的一个知识点就可以用上了,那端口是8889。8889好,这个地方一旦拨号呢,会得到一个连接和一个L。会得到一个连接和一个温,那做一个判断,如果L不等于六。好,那如果它不等于零,就代表我们这地方连接失败了,那肯定这个就没法玩了,针对这一个登录就玩不了了啊,那就打印出一句话。打印机打印出一句话,打印出一句话好,这句话呢,我们叫做net。
25:03
然后呢,A。等于一个L,然后呢,我们就return了,不玩了。好,这个OK,那么如果说对方没有报错,那说明我们怎么样连上了,那连上呢,诶你就可以发一个东西过去了,现在开始发了啊,现在第二步。准备。准备。准备通过。通过这个conn发送。发送消息给服务器。给服务器。怎么办呢?不要忘了这一步了,开始了啊,看我们这边分析的,先创建一个message结构体,因为你发的时候,你发的结构体啊,你发的结构体,所以说你二话不说先搞一个结构体。整出来再说VR。Message。Message好,这个message呢,它的它的这个类型是。
26:00
My message这个包包就是这个包包里面的啊啊,这个包叫common,不好,我干脆就叫message吧,我换一个包包啊,呃,取个叫message message包下面有这些message嘛,好,也也很好理解,我就叫message吧。好,Messages包包下面。第二。点什么玩意儿呢?就是我们的这个message结构体先给他一个,但是这个时候呢,它是空的,没用好,这个时候我们先可以把类型给他,就是这个发送的类型先确定下来是message。第二哪一个哪哪一个消息呢,是属于这个登录的这种消息,大家看我已经做了第一。第一个设置。但这个不够,因为里面呢还有一个特别重要的就是一个data,这个data呢,你先要去创建一个logging message,把东西复制好了,序列化填进去过后才行,所以它的步骤第二步对消登录消息这个地方,你要先序列化过才给它传进去啊,所以说第二步这个步骤比较比较有意思啊。
27:12
好,下一步走第三步。第三步,创建。创建一个什么呀,Logging。Message message这个结构体,因为你要去做这个,所以说这个很简单,我们就直接写了啊,Logging。啊,Message好的等于什么呢?那这这这个它就等于message这个包包下面的logging message。但是他现在是空的,往里面给我填东西吧,各位朋友填什么东西,第一个把ID给他。他这里面因为这个这个消息里面呢,有一个user ID。没问题,ID没问题。好,这个UID呢,咱们先给它放好啊放好,哦对了,呃,我这个地方还有一个小问题,同学们注意听啊,我我写到这,我突然回想我刚才代码写的有点小问题,哪里就这。
28:12
我们目前嗯,这些消息啊,看到没有消息也好,包括log me也好,它的前面这个字段呢,都是大写的,但是我们区我们往往呢,需要他在传递的时候,序列化的时候呢,呃,他这个都是都是那个小写的,所以说我还想用一下那个,呃,那个刷的T,我我把这个补一下。这个大家应该是理解的啊,先森走。我这顺带就把它处理了。就是我全部给一个呃,结构体的标签,这样子呢,我后面得到的呢,都是小写的,那我这大写的原因是因为我要序列化啊,因为你将来肯定是结构体要序列化才能才能才能发送的好,其他以此类推。我序列化一下啊,同学们。嗯,OK user ID这里全部做一个处理。
29:02
密码。OK啊,这边是user密码这边。走,说说这边到了user name user name,好,这边呢,有个code ID code ID。扣的OK,这有一个A啊,相当有个AER2好,这个就就补全了,补全回回回头再这边接着写。好,这个地方不值还是大写的啊,因为你的还没是用序列化嘛,所以说它的字段名仍然是UID。那这个把ID怎么传给他呢?你这不有了吗。来给他。紧接着他还有一个重要信息,Logging,威士忌点。Userr密码,密码是什么呢?就是这边传过来的userr密码,这又到位了。好,现在不要忘了一件事情啊,你准备要发送,你得把这个message。
30:02
给到这个mes的得塔这个字段,但是现在能不能这样给各位朋友,我能不能这样写说老师你现在不写差不多了吗?得塔等于这个不就完了吗?行不行?行不行,这样干。小乔行不行?我我我我来,小夏你说。这样能给他吗?彭静,你这样子行不行?为什么不行呢?对,这个是什么呀?对,所以说你是不是先要把它进行一个序列化给它放进去啊,哎,对了,同学说的很对啊,所以这个是错的,这种写法是不对的,那么应该先做第四件事情,将。讲什么呢?讲我们的这个logging。
31:03
Log message序列化。序列化,这个在前面咱们学过吧,杰森第二。什么玩意儿?Aha。然后这个序列化的时候呢,你得把它给我扔进去。那扔进去过后,他返回了一个data,还有一个什么L。OK,那这个时候这个data塔它的类型是一个bit切片,是不是是个bit切片,所以你先做一个判断,如果L不等于零二,如果它不等于零二,就代表我们虚拟化出错了。PNTN。好,我们提示一句话,叫Jason Mar e。好的,它有个L等于什么呢?CC好这个就不玩了,走了不玩,那如果在序列化成功。那么这个时候这个data就可以填到。
32:02
这个data就是我们这个东西了啊,但是呢,你要这样转,因为它是一个这个data塔,它是一个带的切片,而人家这个得塔的型是十寸,因此呢,你要先把它转成十寸再给它。好,转成给他。过到这一步,我们的message就既有了data,又有了type,这个type仍然是一个字符串,同学们,因为我给的是一个常量,这个常量是字符串常量。好,DD这个是第五步,第五步是把什么呢?把这个得塔贝塔负给了我,或者填充到啊就可以给了付给付给谁了呢?这个message的。Message data字段。好,第六步。第六步该干什么事情呢?第六步将。
33:01
Message。进行序列化。因为到这个时候,你的这个message结构体才是一个正确的可以发送结构体,再序列化,再序列化,又把刚才这个代码又拿下来为我所用。好,这个时候序列化的应该是message。它是一个结构体,虚的话也拿到一个data,但是上面因为有error,所以这地方不需要。再给它定义,如果L等于零,然后这方仍然是序列化错误。再return,好,同学们,最后这个数据就是我们要发送的数据了,这个数据就是我们要发送数据,它是一个bit切片,它是一个bit切片,现在可以发了吗?现在说明一点啊,七到这个时候,到这个时候到这个时data就是我们要发送发送的这个消息,但是呢,发送的时候,根据我们原先的一个规则,根据我们原先规则,我们是先发送一个长度。
34:06
先发送一个程度,再发送消息本身,因此呢,又有个麻烦事,我们现在要先干一件什么事呢,各位朋友。各位朋友啊,下面这一步。7.1先。先把先把这个data。贝塔的这个长度。长度。发送给。八送。发送给服务器,服务器因为我们为了防止丢标,我们先让他知道说告诉你啊,你应该先给我接收多少个多少个这个呃,字节的字节的内容,那这个对我来说小意思嘛。怎么发呢?首先有同学说,老师太简单了,看。第二。所以有一种可了点,Right。
35:00
然后这个地方把这个data放进去,想这个不行啊,这个发的是内容本身你也不能这样写,认识也不行,因为这个认识啊,同学们,这个识返回的是个int类型,你这一保存马上就报错了,为什么这样说呢?因为right它发送的是。带的切片,你们来打开这个手册看一下啊,这地方要有个转换很麻烦的,很麻烦,这地方很多同学不理解啊,这地方就是工作过一段时间的,他只要问一下来做,他不一定能想明白怎么怎么弄好,同学们看,首先现在你把这个长度怎么发。啊,我们来找一下这个手册啊,注意听,同学们注意听go官方。官方文档。我不来东西。往来揉一点,看一下这个地方是怎么回事。首先我们找到net包,Net包,这对我来说很熟悉的一个包包。Net包,Net包呢里面有一个right方法就是connect,这个connect呢,是我们现在最重要的一个结构体啊,它应该是个,它应该是个一个接口啊,接口里面有个right,看到没有。
36:10
但是right呢,它发送这个实际上是一个bit的一个切片,所以说这地方你还不能直接按照这种的长度长度来发,还很麻烦,你还得这么干一些事儿,还得干一些什么事情呢。先注意听啊,先获取到这个得塔的长度,然后将这个长度转成。一个可以表示这个长度的切片。这个有点麻烦,表示长度的。长度的切片啊,这个拜的切片。啊,这个有点麻烦啊,那我告诉大家怎么处理。怎么处理呢?这里面有一个特别重要的方法要跟大家聊,这样发肯定发不过去的,这样发绝对错误,你发过去他他编译都错误。
37:01
别动错,那么怎么把一个长度转成一个切片呢?各位同学,我给大家看有一个包包,这个包叫什么呢?啊,Encoding bay encoding bay找一下。Including including在上边儿就这。好,再看这里。BA包实现了简单的数字,简单的数字与字节序列转换的一个方式,那它可以把你的一个具体的数字转成字节序列,说白了就讲转成我们的这个字节码,字节码里面有一个特别重要的方法。是什么方法呢?好,是这个有一个叫做bit order,这个bit order呢,它里面定义了好几个方法,其中有一个方法叫做put。Unit,呃,我们用这个put unit32,它这个地方是你你把一个UNIT32的一个具体的数字填到这儿。
38:06
然后再给他一个切片,这样子就会把这个数转成一个be的一个切片的序列。那这个可能同学们第一次接触,有点不太理解啊,有点不太理解。好,那我先写一下,写一下来看我的思路,这个肯定不行。第一步,我们先来一个package。Package我就简写啊,Package一个字,一个一个一个包包,它叫package,那简写叫PKG。我要发出这个包的长度等于我先给它来一个这样的值,VR大家看看能不能看懂。U。INT32。为什么我把它定成U32呢?因为它是个一个无符号的,呃,三二这个这个数呢,能表示的一个数据量比较大,这是第一个原因,第二个原因呢,就是因为待会我想使用的是这个方法。
39:05
Put unit2,如果有些同学说老师,那我如果想使用put unit unit unit64呢,那可以,你你可能就是想发送的数据量更大嘛。那你就把刚才老师写的这个呢,改成U64,但是我觉得没有必要,我觉得三二应该很大了,就一次性把这么大一个字节,你想U1的三二,它应该能相当于发多少个多多大的一个数据过去了,你可以算一下啊呃,三二的话就是那个二的32次方,因为它是无符号的。再减掉一个一。它这么多个字节,这么多字节和多少兆呢?那就除以1024,这个就是多少K,再除1024,这就是兆,再除一个1024就是G,也就说你已经可以发三个将近四个G了,我估计一般来说网络都快都快充死了,足足的够了啊,所以暂时没有必要整那么大,因为你不可能一次性的发一个东西发四个G的。
40:07
而且网络肯定也也撑不住对不对,所以说呢,我觉得这个UNIT32目前来说足足的够了啊。足足的够了,那现在开始做这个事情呢,长度放进去怎么放呢?VRVR好的这个长度先把它算出来,PKG。PKG等于。等于多少呢,嫩?嗯,把这个data放进去。啊,但是这个嫩,这个嫩呢。这个,那算下来它返回的类型大家都知道,它是一个什么类型,还记得吗?它是一个int类型,把一个int跟一个u u int32肯定是不行的,因此呢,要进行一个强转。这样子大家看能不能理解。
41:00
啊,这样就可以了,就说现在这个PKG已经PKG这个嫩已经有了,但是呢,你还要把它放在一个切片里面去,好,这个呢,就是先定一个切片。先定一个切片,比如说我就叫BY吧,BY切片。Bed,这这这是一个切片,我给他来个四个吧。来四个就是表示呢,呃,这个就是个数组,可以先定一个数组啊,往里面放东西,呃,那么我们这叫这叫BY次啊,我看看地方咱们取个什么名字啊。就叫bit。好这样子,这样子。然后呢,我们往里面放东西啊,我们往里面放东西。怎么放呢?呃,用这个binary一个包,呃一个方法,大家看一下bay一个包。呃,四这是四啊,这是四,这是四没没没有问题,那我写一个这样的东西,就是怎么写呢。
42:02
他有个battery。Bay。这个battery包里面有个方法,哪个方法呢?它这里面有一个这样的东西叫big,它有个变量叫big a点这个这个你什么啊,End end,好,也不要怎么去念它,管它是什么啊,先用它。走点。它这里面就有一个方法了,就是它的这个类型,它的类型是什么呢?是这个类型。啊,这个类型其实就是bit order,就是字节序列的一个类型,里面呢,就有这个方法。好,我把这个方法复制过来。复制过来,复制过来呢,我往这儿一放,然后把什么东西放进去呢,把它放进去。好,把它放进去,我要做一个切片,切片我就是认为从零到四。其实就是把四个全全部拿到了,拿到拿到过后我们再来做一个东西,什么呢?就是把这个pick放进去。
43:09
啊pack啊pack这样子呢,就相当于说我把这个长度转成了一个BY词。好,转成筷子,现在就可以正式发送了。啊,现在发送这个程度。发送长度。好,那么这个发送长度怎么发呢?好办,那就用这个题了。connect.right。然后我们要发送的就是这个拜。啊,发送的就这个白词,那么发送完了过后呢,这边会返回一个N,还会返回一个error,大家都知道,这个我就不多说了。对,那么我们现在怎么知道它发送成功了呢?那首先它应该一共这个N必必须等于四,如果它不等于四,就说明它失败了,或者这个A不等于near,说明它也失败了。在这两个条件,只要有一个条件成立,就说明我们这个发送没有成功,就这个长度没发送成功,我写一句话。
44:10
好,我说失败。好大,大家看一下啊。失败fail原因。L打出来往后走不走了。好,同学们到此啊,到此我们这个就。长度已经发出去了,但是我这个代码呢,有一个缺陷,就是当这个connect拿到过后呢,我应该马上及时的来一个延时关闭。你这个延时关闭啊,同学们不要小看这一点。如果小这地方没有写对,少了一个延,延时关闭后面那个,后面写个代码的时候,你你你那个错误非常的诡异,还很不好调。这个也是一个坑,但这个坑呢,又被韩老师给你们直接填平了,其实准确的一个讲法是先挖一个坑让你们进去,然后呢,我在这个坑外面说,诶诶挺好玩,我把你捞起来对吧,捞起来过后咱们又继续往下走,又有坑,我让你先栽进去,哎,老师又把你拎出来,这样你成长的又摔了几只坑嘛,大家那个腿就有点有有点力气了,如果在一路刚走到这个坑的时候,老师诶不要走那边啊,小心点,然后你们就绕过去了,那以后你们掉坑里面的时候呢,你们可能就不来了啊,所以这个地方按理说应该给你们,给你们留一个坑,但是我我害怕自己掉进去过后我也起不来,所以说我先把它写进去啊,我先把写上,因为这个可有时候你代码现在还比较少,代码代码越来越多。
45:41
一旦出错了,大家看这个代码你去调吧,你自己看到,而且它是这边的错误,可能是因为你的那个服务器导致的,调起来很麻烦,因为他这个是他,也就是说将来这个错误是什么呢?比如说你客户端出错了,可能是服务器端的一句话忘写了。所以这网络网络的编写的这个这个复杂度会比较高,会偏高啊偏高好了,那不管怎么样,我们继续写吧,这这还快完了啊,就是第一步快完了,现在他不是已经发出去了吗?好,我们再写一句话。
46:16
现在一步来说客户端。客户端。客户端。发送。发送数据,数据发送这个消息,消息的长度,长度成功就是我们这个长度长度成功就是现在我们已经把这个消息的长度发出去了,但消息的本身我还没发,因为消息本身实际上是data。我还没发号,因为我按照我的逻辑是我先给他发程度,我再接着发消息本身。好,当然有些同学说是我能不能合在一起吧,也可以也可以就说那你这样的话呢,你这个message里面再加一个字段,就是每次把那个消息放进去。啊,那你那个字段要设成一个切片才行啊。
47:02
因为你你你不能写,不能那芯片很麻烦,好了先按我的思路走吧,好这样做完了以后呢,同学们这边代码一保存有大量的错误,一共有八个错误,主要的原因就是没有引包,把包一堆全引进去。第一个包包,Encoding。Encoding第一个包节省。第二个包BY。这个battery呢,就是用来做这个转换的啊。Bary OK OK,好,第第第三个包包。保存好像应该就没错了,还有五个,我看一下message没有引入我们的这个,呃,这个message这个这个这个吧,啊,那就写一下go。Code,然后呢,Chat room。Charter room。当然,下面有我们的一个common。啊,Come,下面有我们的message,好,再保存O了。
48:03
还有一个错误啊,看一下在哪里,呃,在哪个地方呢,是不是有个没有返回啊。呃,在这里他可能认为有。我。我找不到呢,保存一下啊。保存一下。嗯。没了。没了,可能是当时那个没有没有没有保存全对吧,没没有保存全啊对他那就没有就算了吧,没有就算了吧,那没有错误,大家还还那么痛苦,就就说不过去了,对吧?好,这边写完了过后不要着急,我们现在呢,要开始在这边接收,不是那边一直等着你的吗。那客户端一直等着你的,好客户端来吧,各位朋友找到啊,服务器端啊,服务器端他一直在等待,他已经等待的有点不耐烦了啊,这个链接拿到了,那连交他就读嘛。哎呀,我天怎么去读它呢。For循环我就一直读,因为我这边我这边是要我这边可能要一直等待,就说我我一旦拿到过后,我就可能一直想给你读,对不对,同样这边也有一句话,及时关闭,这个也是个坑。
49:12
这里需要需要延时关闭,延时关闭这个。关闭这个connect,如果你不关啊,你会发现也也会有些非常奇怪的现象。非常奇怪现象。你做过网络开发你就知道了啊,Close。OK。所以我们看到这些网络开发,我们有点似曾似曾相识的感觉,因为我最早刚刚工作的时候,我们就说这个数据通道,然后当然那个时候用C写的啊,那C写C写的代码比这个复杂多了。那那个代码一般都看好久才能看懂,我刚刚,而且刚开始没有什么经验,后面有点经验的时候呢,呃,这个就又去干别的活了,好所以永远都是这样子的,不停的在学习,不停在学。Listen OK,这这个地方哪,这这。
50:06
你把这个关闭干啥,你又关闭了,你下一个还还玩啥。哦,你说这地方延迟关闭这个倒这个倒不一定吧。我们以前写的有吗?这个地方是怎么写的呀,Differ是吧?啊differ那就做一下。对,可以。呃,点close非常好啊。很好,很好。是这样子的吧。Close延迟关闭就无所谓了,反正它不出来还不关嘛,对不对,它不出来不关无所谓,好现在我们来在这循环的读取啊,循环加这句话循环的读取。循环。循环的读取客户端发消息,那首先这个地方我们先直接来一把啊seven.read。那么你在read的时候呢,也要做一个切片,所以说呢,我们在读的时候,各位朋友读的时候这边是准备要读了,读的话呢,我们先准给他开一个切片先。
51:10
前面我们已经讲过这个东西了。啊,切开一个切片,那就是bit,呃,我们是怎么写的啊,Bit bits啊,我们当时是用的一个buffer,对对对,同学们说的很对啊,Buffer buffer啊,OK buffer,对,说的很对。Buffer buffer走make,我们先给它来一个,给他画一个空间,就是这个bit切片,因为读的时候它是按也是按这个切片来读的,给它多大呢?咱们尽量给它大一点吧,啊,比如说八按照1024乘以四啊。按照这么大一个来读,那就8080980968096先开大一点啊,注意那读的时候呢,同学们读的时候我只读前面的。
52:00
这个四个,因为你给我发的是四个,我也读四个字字节,这样才能才才是对的啊,这里很重要,如果你不有没有四的话,读的很多,把后面的那个呃,没有用的东西也给你带过来了,就麻烦了,那这样读到一个N,读到一个L。好,这个时候呢,我们就要一个判断,判断判断,如果N不等于四,因为我读要读四个字节,你给我发了四个字节,我也读四个字节,如果它不等于四,或者A不等于near,说明什么呢?说明我这个读就读错了。说明这个读就读错了,好,那我就写一句话。就说明我读错了,那就说咱们这个cor a出错了。OK,那把这个错误打出来,把这个错误打出来,ER等于L。他这个如果如果一旦读错了,你可以,呃你看你怎么处理了,就是一旦读错的话,要么你就要么你就干别的事啊,假设我就return了,我就不玩了,注意这个地方会阻塞啊,如果你如果你这个呃,你这个读不到东西,它会堵在这个地方,前面我们讲过这个原理好读到过后呢,我把这信息打出来。
53:15
我写一句话啊,读到。读到的这个,呃,这个长度为八份的,八份等于多少呢?输出来看一下。输出来看一下,它是个,它是个BY的切片数组。BF好,把它打出来之后,又回头再再再来读,那为了好看呢,我这给他一个提示。我再给他一个提示信息。我刚提示疫情期,说等待就是呃,等待读取啊,读取一一指吧,读取读取客户端,客户端发送的,客户端发送的数据。发送的数据。OK。好,呃,这叫buffer,那干脆我们这边也把名字改一下,把名字改成一样吧,这边发这个长度呢,咱们也取个名字叫buffer吧,别叫BA了,怪怪的啊,Buffer。
54:10
这样子呢,大大大家都统都统一八分啊。这样我们我们都都这样做,八分。好,现在这边老井这边有问题要引包。Barber。要加切片。幺幺切片。要要切片对。加切片,因为因为这边它本身是个数组,对吧,要加切片好捞进这边有一个小错误,还有一个错误。呃,这边还有一个错误,是在这儿看一下错误的原因。他应该说少了一个return,果然少了一个return啊,因为你这他他担心什么呀,他担心你这个地方if进来了,那没有进来怎么办呢?所以他不担心这个问题,所以最后加个return就行了。啊加个,因为你这边是有个error,你是命名的,你是命名的,所以这个error呢,它会带过去。
55:03
好,服务器这边也写完了,都写完了啊,来各位朋友验证一下我们代码到底有没有成功。好,我们看看到底这个这个长度有没有成功,准确说他应该得到一个长度,就说我这个log message长度是多少。来,我们来跑一把跑一把啊,郭同学,验证它到底OK还是不OK。这是我们的。我要起两个了。因为一个没办法做测试。我要起两个两个两个。找到go project,进到这里面去。好,各位同学验证一下。这边呢,我们把这边当做服务器吧。把这边这个当做客户端吧。来,往这边挪一下,往这边挪一下。先启动我们的服务器,先编一下。
56:02
Go。A build go,先build一下BB。杠O,我们直接给它生成一个名字server.exe,然后呢,Go code_code,然后呢我们是chart room。然后呢,我们是server这个包包。对,Server这个包包OK。好,现在呢,我们应该看到有一个server了,我们把它提起来。他说。服务器在8889端口上监听。等待客户端连接正确的。紧接着我们这边呢,也把这边客户端进行一个编译。好的,编译成功,我们来走一个C。好,他说你准备干什么事情,我准备登陆。好,我输入我们的一个这个ID号,比如说100。
57:03
而用户的名字呢,ABC。好,同学们可以看到此时此刻我们这边他因为我这没有做任何的验证,我就是说客户端发送,客户端发送消息的长度,我们呃,成功了,登录成功,那这边服务器端这边接收到这个数据,大家看到很奇怪这么长。这是因为我在打在输出的时候呢,我是把整个这个八分输出来,其实准确的讲,我们只接收到了前面这个。是吧,那你为什么打了这么多呢?是因为我输出的时候我没有做,没有做这个控制,我在输出的时候这样输的肯定不行,理论上说应该输到四就可以了,因为我只读到第四个字节。这是一个,第二个呢,我们来看这个长度对不对,怎么样验证你的长对不对呢,我在客户端把这个长度输出来。就说我发送完了过后,我就写一句话,我说客客户端发送消息长度OK,应该是多少呢?好,我们算一下它真实的长度,就应该是嫩去计算这个data。
58:06
这个长度就是这边应该收到的长度,我们看对不对啊同学们,我们看对不对。好了,大家看啊,我这还没有做那个没没有做那个真正的校验,只是我一发,我也没去看他到底有没有成功,直接就走了。当然后面马上就要根据对方就服务器那端发过来消息来判断你到底OK还是不OK,因为我们目前没有回送这个,还没有回送这个lot response message。我没回送,他就直接认为我,我下面也没有做判断对吧,我就直接说都都成功。好,再来再来跑一下这个长度保保存一下,各位同学来重新来跑一跑。看长度对不对啊,首先。重新来玩一把。Server进行一个编译。Server编译,然后呢,运行我们这个可爱的server。好客户端,客户端这边我们也编一下。
59:02
变一下,然后呢,我们运行好轴ID等于。这个。100。密码,汤姆。各位同学请看,应该是对应上了,我一共发送的消息长度是83个,这边也说我收到了83个这个长度发过来,当然有同学说老师你能不能让我看一下我这个到底发的是什么内容,可以,如果你要看你到底发的是哪个哪个内容,其实就是把这个data转成十寸。就可以了,这些你们要学会调试啊,那么我们把它具体的数据成出来,就是内容是这个大家会看它,这么是要把按字符串来看,那是寸贝塔来看一下,对不对啊,同学们再跑一下。嗯,服务器端这边不用不用管它服务器,因为它还在等待监听,它又在准备读取,那我这编一下走。
60:01
再走一个啊,同学们看走跑起来走ID100,这次来个abcd回车,好84个,那么我们真正发送的内容其实就是它。这个就是我们序列化的东西,那这个序列化这个到底它有多长呢?很简单,你把它写在一个文件里边。写在一个文件里边,然后把它保存起来,保存完了过后保存,然后来点一下,看看它到底有多大,我们一看发现的确是84个字节。说明一个都没漏掉,好同学们到此为止啊,我们经过经过一番这个折腾过后呢,我们终于完成了第一步,把长度发过去了,当然你只要把这个网络一打通,后面的内容呢,相对来说就比较轻松了,但是也不是那么容易,因为后面我们要涉及的问题也很多,第一个大家看目前我们写的代码很松散。
61:03
没有结构,而且你发一个数据和接收一个数据,完全没有一个函数封装,这样子肯定是不行的,复用性很低,因为你将来这个收发这个消细胞太多了。后面涉及到一个函数的封装和一个程序结构的改写,好,我们先把这段代码呢给各位同学整理一下,OK,确定message消息,然后。啊,然后根据根据上图的分析啊,分析完成代码。那么我这边有个示意图。示意图。那这个示意图呢,是怎么画的呢,各位朋友。是这样画的啊,这样画的。当然,呃,你可能看你你感觉好像,哎,怎么韩老师一写都就过了呢,你们去写试试看啊。我跟你说,你们只要是没有注意的话,你你估计要写好久你才能通啊,你这个这个可你们自己待会去试下。
62:02
这这个就是就是要要去多多多锻炼才行,那么具体代码呢,我们把它写出来具体代码。代码实现,代码实现是这样实现的,各位。好,我把这个代码给他整理一下,我们写了哪些代码呢?捋捋捋捋捋思路啊,首先我们先看服务器端server这边。Server这边我们写了个main点构,现在还没有程序结构啊,还没有程序结构,老师呢,是直接写到server点构,我是写到这了。好,这次呢,我就不能粘源码了,我需要你们去写写。第26行。OK。OK,第26行,然后呢,接着往下截取。26。好的,这边是第27行。27到下面一堆。27到下面一堆。没问题。好,这是客户端啊,服务器端这边,客户端这边啊,中间还有一个啊,先把中间的锁在common这个包包下面有个message。
63:08
Message这个包下面有个message,点够。好,这里面呢,我们定义了这一个message的结构体,对不对,好,这个结构体呢,也是非常重要的。这个结构体对我来说也是至关重要。后面还可以不停的增加,你看这个结构你们应该可以看出来了,它的扩展性会非常的好。你明显能感觉到它的扩展性会非常好,以后你要你要加一个什么群发的信息,用户在线的信息都是信息,他结构不一样,所以说这个一组装就会马上形成一种新的消息,这个这个结构啊非常的非常好,那么我也把它写到这里了。好,紧接着呢,我们再来看,我们还写了哪,然后呢,Server。呃,啊,Client呢,我们这边client。我们写了一个main.go我们还写了一个client。
64:02
下划线locking订购。好,那这边我们怎么写的呢?各位朋友,我们是这样写的。首先看main,点勾main点构跟前面是一样的,不用改,这个跟前面一样,我写一句话就行了。和前面的。和前面的代码一样,代码一样没有修改。没有修改,没有修改。好,那么我们这个河南log这块是怎么写的呢?啊,实际上写的这这段代码稍微长一点啊,这段代码稍微长一点。OK。到第26行。第26行。好,第26行呢,接着往下截去。第26行。好,第27行。第20项第20项。好的,这是第27行。到51行了。
65:00
好,第51行接着截取51。到第52行。这里面有一个地方是同学们一定要去理解的啊,就这个地方很重要。先获取data的长度,转成一个表示长度的切片,那具体来说我用的这个方法呢,是这个原因我也讲清楚了。好,然后呢,我把它包一下。好,同学们,这个代码就写完了。关于这这个功能就是用户登录过后发送的一个消息的长度,我们先给大家讲到这里。
我来说两句