第八季-双人对战五子棋
- 01.计算机网络基础
- 为什么有网络?
- 网络的定义
- 什么是网络协议
- 网络的层次模型
- 分解
- 物理层
- 数据链路层
- 网络层
- 传输层
- 会话层
- 表示层
- 应用层
- IP地址(Internet Protocol Address)
- 字节-位
- IP地址=网络地址+主机地址
- IP地址分类
- 02.TCP-UDP
- 端口(Port)
- TCP 传输控制协议(传输层)
- 特点:
- TCP数据报格式
- TCP控制位
- TCP连接
- 建立连接/三次握手
- 断开连接/四次挥手
- 为什么TCP发送的消息能保证可靠性呢?
- UDP 用户数据报协议 (传输层)
- 特点
- 应用场景
- Scoket 套接字 (传输层)
- 03.HTTP请求
- 长连接和短连接
- HTTP 超文本传输协议 (HyperText Transfer Protocol) (应用层)
- HTTP Request
- HTTP常见状态码
- XMLHTTPRequest
- 代码
- Chrome跨域问题
- 04.NodeJs
- 什么是NodeJs
- 安装依赖库
- ts转js并运行
- 05.WebSocket
- 什么是WebSocket
- 安装依赖库
- 使用WebSocket
- 手机连接电脑
- 06.五子棋--数据UI分层
- 07.五子棋--添加玩家
- 08.五子棋--胜负判断
- 09.服务端匹配
- 前期准备
- 配置入口文件index.ts
- 编写客户端
- 10.五子棋--网络通信
- 11.数据库基础
- 解决数据持久化存储问题
- 数据库与运行时内存的区别
- 关系型数据库
- 介绍
- 举例
- 优点
- 缺点
- 文档型数据库(非关系型数据库)
- 介绍
- 举例
- 优点
- 缺点
- 总结
- 12.MongoDB
- 安装MongoDB
- MongoDB术语介绍
- 常用命令
- 13.NodeJs连接数据库
- 安装NodeJs依赖库
- 服务器连接数据库
- 14.注册流程-服务端
- 前期准备
- 代码
- 插一嘴
- 15.注册流程-客户端
- 16.登录流程
- 快捷启动MOngoDB
- 17.匹配流程
- 18.断线重连
01.计算机网络基础
为什么有网络?
为了能让计算机和计算机之间相互通信.
网络的定义
计算机网络是由多台不同功能的计算机,通过传输介质,连接起来.以传输协议为约束,进行通信的一个网络.
什么是网络协议
网络协议为计算机网络中进行数据交换而建立的规则,标准或约定的集合. 作用类似于普通话.
例子 0001 0010 1101 0010 1011 1111
协议:前四位表示这串数据的类型,第二个四位表示后面数据的长度…
网络的层次模型
网络可以分为四层、五层或七层,七层是最标准的。
学习计算机网络就是学习每一层的协议是什么.对于传输层,网络层,数据链路层,物理层的传输协议要求不是很高.重点是IP协议个应用层的协议.
分解
TCP/IP是一堆协议的组合,是应用层、传输层、IP层、物理网络层的协议统称。
物理层
该层为上层(数据链路层)协议提供了一个传输数据的可靠的物理媒体。简单地说,物理层确保原始的数据可以在各种的物理媒体上传输。(比如说光纤、网线)不同的物理媒介有不同的协议。
数据链路层
将源自网络层的数据可靠的传输到相邻节点的目标机网络层。
基本数据单位为帧。
主要协议:以太网协议
两个重要设备名称: 网桥和交换机
**简单理解: 将数据打包成数据块,数据块在数据链路层进行传输,每个数据块就是一帧。数据传错了,丢失了都是数据链路层进行处理。
网络层
实现两个端系统之间的数据透明传送
基本数据单位为IP数据报
包含的主要协议:IP协议、IMPC协议、ARP协议、RARP协议
重要的设备:路由器
IP协议:因特网互联协议
提供不可靠的没有连接的传送服务
无连接的数据报传送、数据路由的选择,差错控制
IMPC协议:因特网控制报文协议
不负责数据的传送,包含网络是否可达和路由本身的一些消息
ping 就是ICMP协议
ARP协议: 地址解析协议
根据IP地址找到每块网卡的物理地址
RARP协议:逆地址解析协议
和ARP协议做相反的事情
根据物理地址获取IP地址
传输层
传输层负责将上层数据分段并提供端到端的、可靠后不可靠的传输以及端到端的差错控制和流量控制问题
包含主要协议:TCP协议(Transmission Control Prorocol,传输控制协议)、UDP协议(User Datagram Protocol,用户数据报协议).
重要设备: 网关
王者荣耀就是UDP协议,是不可靠传输,但速度块.
TCP是可靠协议,每次传输后都会进行验证,保证数据是准确的,按顺序收到的.
会话层
会话层,表示层,应用层都是可以在代码中进行实际的控制了
会话层管理主机之间的会话进程,既负责建立、管理、终止进程之间的会话。会话层还利用在数据中插入校验点来实现数据的同步。
表示层
表示层对上层数据或信息进行变换以保证一个主机应用层信息可以被另一个主机的应用程序理解.表示层的数据转换包括数据的加密、压缩、格式转换等。(是否加密、压缩、格式转换等都是我们可以控制的)
应用层
为操作系统或网络应用程序提供访问网络服务的接口。
会话层、表示层和应用层的重点:
数据传输基本单位为报文(可以理解为数据包)
包含的主要协议:FTP(文件传送协议)、Telnet(远程登录协议)、DNS(域名解析协议)、SMTP(邮件传送协议)、POP3协议(邮局协议)、HTTP协议(Hyper Text Transfer Protocol)。
应用场景
FTP:从论坛上下载文件
Tenlnet:在我们的电脑上登录服务器
DNS:将域名www解析成IP地址
SMTP和POP3:收发邮件
HTTP协议:浏览网页
IP地址(Internet Protocol Address)
在网络上能表明我们本机地址的格式.每台计算机都有一个公有IP和一个私有IP.
现在计算机太多啦,IPv4 32位快不够用了
字节-位
一个字节是八位
一个字节能代表的最大的数的255
IP地址=网络地址+主机地址
最大的IP地址就是255.255.255.255
例 192.168.0.1
192.168.0是网络地址
1是主机地址
一台路由器连接了一台电脑主机地址是1,又连了一个手机,主机地址就是2,再来个平板IP地址就是192.168.0.3
一个网络下最多承载254个主机(为啥不是255,之后讲)
IP地址分类
- 只要第一位是0就是A类地址.
- 一般家庭就是C类地址
私有网络
A类: 10.0.0.0,保留了一个A类网络
B类:172.16.0.0 ~ 172.31.0.0,保留了16个B类网络
C类:192.168.0.0 ~ 192.168.255.0,保留了256个C类网络
不在这些范围内的就都是公有IP
例如192.167.0.1肯定是公网IP
特殊IP地址
1.主机ID全为0的地址:特指某个网段,
比如: 192.168.10.0,指192.168.10.0网段
2.主机ID全为1的地址:特指该网段的全部主机
比如: 192.168.10.255 (解释了之前为什么最多连254个主机)
3.127.0.0.1: 是本地环回地址,指本机地址,一般用来测试使用.回送地址(127.x.x.x)是本机回送地址(Loopback Address),即主机IP堆栈内部的IP地址.
4.169.253.0.0: 169.254.0.0-169.254.255.255实际上是自动私有IP地址
5.0.0.0.0: 如果计算机的IP地址和网络中的其他计算机地址冲突,使用ipconfig命令看到的就是0,0,0,0,子网掩码也是0,0,0,0 。
02.TCP-UDP
先回想下TCP/UDP是哪个层的传输协议?
端口(Port)
在网络技术中,端口(Port)大致有两种意思:
- 物理意义上的端口: 比如,ADSL Modem、集线器、交换机、路由器用于连接其他网络设备的接口(网线插在哪);
- 逻辑意义上的端口,一般是指TCP/IP协议中的端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等
每一个进程都会监听自己的端口.
网络连接需要知道对方的IP和程序监听的端口号
TCP 传输控制协议(传输层)
通过TCP发出的消息都能保证对方接收得到并且是完整的。
特点:
- TCP负责发现IP层传输的问题,有问题就要求重传
- TCP是面向连接的通信协议,通过三次握手建立连接,四次挥手断开连接
- 通过滑动窗口进行流量控制,滑动窗口表示计算机接受能力,用来限制对方发送速度
TCP数据报格式
- 头部固定是20个字节
- 源端口:从哪发出来的消息
- 目的端口:发送目标程序的端口号
- 序号:此TCP消息在第几个位置
- 确认号:只有在ACK标识为1时才有效,代表目标期望的收到的下一个字节流是多少,之后会细讲
- 窗口:接受能力是多少
- 检验和:进行校验,确保收到的消息和发出的消息是一致的
- 紧急指针:偏移量
- 选项:可能会带一些时间戳、窗口扩大因子等等
- 填充:把消息头补完,固定20字节
- 头部之后就是我们要发送的消息,组成了TCP包
- TCP包传输到网络层就会将TCP包作为IP数据报的数据部分加上IP数据报的头部组成IP数据报
TCP控制位
控制位:URG ACK PSH RST SYN FIN,共6个,每一个标志位表示一个控制能力。
- URG: 紧急指针标志,为1时表示紧急指针有效,为0则忽略紧急指针
- ACK:确认序号标志,为1时表示确认号有效,为0表示报文中不含确认信息,忽略确认号字段
- PSH:push标志,为1时表示是带有push标志的数据,指示接收方在接收到该报文端以后,应尽快将这个报文段交给应用程序,而不是在缓冲区排队
- RST:充值连接标志,用于重置由于主机崩溃或其他原因而出现错误的连接。或者用于拒绝非法的报文段和拒绝连接请求
- SYN:同步序号,用于建立连接过程,在连接请求中,SYN=1和ACK=0表示改数据段没有使用捎带的确认域,而连接应答捎带一个确认,即SYN=1和ACK=1
- FIN:finish标志,用于释放连接,为1时表示发送方已经没有数据发送了,即关闭本方数据流
TCP连接
建立连接/三次握手
- 客户端—SYN→服务器 :“我要向你发起连接啦”
- 服务器—SYN+ACK→客户端:“我知道啦,我准备就绪了”
- 客户端—ACK→服务器 :“我也准备好随时接受数据啦”
经过三次握手之后,连接就被建立起来了
断开连接/四次挥手
- 客户端—FIN→服务器 :“我要关闭连接啦”
- 服务器—(DATA)ACK→客户端:“好的,发完这个数据我就准备撤”
- 服务器—FIN→客户端:“我已经准备好关闭了”
- 客户端—ACK→服务器 :“好的我关闭了,再见”
四次握手之后两端就同时关闭连接了
简单来说是“先关读,后关写”,一共需要四个阶段。一款客户端发起关闭连接为例:
- 服务器读通道关闭
- 客户机写通道关闭
- 客户机读通道关闭
- 服务器写通道关闭
为什么TCP发送的消息能保证可靠性呢?
假设发送方是客户端,接收方式服务器
- 开始建立连接的时候已经通过TCP包头告诉服务器我的窗口是多少了
- 服务器告诉客户端自己的窗口是多少,此时双方都知道了对方的窗口值
- 客户端开始发消息,先发个1000
- 客户端计算服务器还能接收,再发个1000
- 客户端计算服务器还剩500个窗口,那就再发500吧
- 客户端等待服务器回执
- 服务器陆续接收到客户端发来的消息,但是并没有处理,还占着窗口位置呢,就像还放在码头上,还没有运到仓库里
- 服务器每确认接收到一次消息就告诉客户端,“我收到xx消息啦”
- 服务器的应用程序从缓存里开始读数据,先读个2000,腾出了窗口的位置,就像将2000箱货运回了仓库
- 服务器告诉客户端,“我清了2000的货啦,能接着发啦”
- 客户端接着又吭哧吭哧发了2000过来
- 服务器再接着确认获取后就告诉客户端"我收到了"
。。。。。。如此循环
每次接收,接收方都会进行验证,如果发现有问题就会告诉发送方,我这个包有问题,你再发一份吧。发送方收到重发消息后就会重新发送一份数据
UDP 用户数据报协议 (传输层)
特点
- 无连接(不用建立连接,都不知道对方在不在,只管发)
- 不可靠(不保证数据会不会丢包)
- 速度快
- 一次发包数据最多1472字节(1个MTU最大传输单元)
一个IP包的最大长度是1500
1500 - 20 - 8 = 1472
应用场景
- 看电影 包丢了也就是花下像素
- 即时在线游戏 网络卡了一下,TCP会一直尝试重发,如果机器性能差,就会网络阻塞了,后面有一堆包在等着传
- 交流频次高,不太需要可靠性的
Scoket 套接字 (传输层)
- 对TCP和UDP进行了封装
- 程序员不必操心数据包头怎么写,三次握手四次挥手的操作
但是也要明白TCP和UDP的工作原理
03.HTTP请求
长连接和短连接
- 长连接:TCP连接一直保持 (保持一段时间,比如20s)
- 短连接:需要发送数据的时候,连接TCP,发送完数据后就断开
HTTP 超文本传输协议 (HyperText Transfer Protocol) (应用层)
- 市面上的一种通用的协议,作用在TCP的上层(封装的TCP)
- 通常用于Web(网页)通信
- HTTP是简单的,可扩展(可以添加自己的需要的数据),无状态的(这次连接和下次连接是相互独立的)
- HTTP可以是长连接,也可以是短连接,由参数控制
(1.0时代只有短连接)
HTTP Request
- Get请求,只获取数据
- Post请求,筛选并且获取数据
例如我们需要获取好友列表,get就是将整个好友列表获取到,而post我们可以添加参数,比如我们只想获取前100名好友。其实两种本质区别不大
HTTP常见状态码
- 401: 表示所访问数据禁止访问
- 403:表示所访问数据受到保护
- 404:错误的URL,服务器资源不存在
- 200:一切顺利~
XMLHTTPRequest
- HTTP的一种,就是http的一种封装,用它可以方便的发http请求
- Creator能用
五种状态
open() 建立连接
初始化HTTP请求参数,例如URL和HTTP方法,但是并不发送请求
send() 发送请求
发送HTTP请求,使用传递给open()方法的参数,以及传递给该方法的可选请求体
abort() 断开连接
取消当前响应,关闭连接并且结束任何未决的网络活动
代码
/**
*@author Qiu
*@description http请求
*/
const {ccclass, property} = cc._decorator;
@ccclass
export default class HttpRequestTest extends cc.Component {
onLoad() {
//拿到request对象
let request = cc.loader.getXMLHttpRequest();
let url = "http://www.baidu";
//打开连接
request.open("GET",url,true); //第三个参数:是否是异步的
//当状态发生变化的时候
request.onreadystatechange = (ev: Event): any => {
console.log("=====request",request.readyState)
if (request.readyState == 4 //request请求已接收 状态
&& (request.status >= 200 && request.status < 300)) { //请求成功 状态码
//请求的返回结果
let response = request.responseText;
console.log("====response",response);
}
}
//发送请求
request.send();
console.log("=======request sended=========");
}
}
运行到浏览器,如下报错
原因:跨域了。因为creator本身预览的时候就是一个网页
实际上就是本地的一个http服务,就不能在去请求另一个域名的http服务,会有安全问题。
Chrome跨域问题
给快捷方式加上
–disable-web-security --user-data-dir=F:/MyChromeDevUserData
- 找到Chrome快捷方式右键“属性”
- 找到“目标”,将上述代码复制到原有字段后边,注意之间有个空格
- 点击“应用”,“确认”
- 打开Chrome,输入本机ip+creator端口号
端口号可以在creator里看
- 此时就能正常跨域运行了
04.NodeJs
什么是NodeJs
- 基于ChromeV8的JS运行库
- 命令行可以运行JS程序
- 在NodeJs官网安装
- 打开CMD运行
node -v
如果出现版本号就证明安装成功
(打开cmd:win+r ,在输入框里输入"cmd" )
安装依赖库
-
打开CMD,进入新建的服务端工程目录
① 先新建一个文件夹
② cmd进入该目录
-
安装全局TypeScript
npm install -g typescript
-
执行
tsc --init
目录下就会生成一个文件
ts转js并运行
在目录下新建一个ts文件,并在文件里写一行代码
console.log("TypeScript Start!");
在该目录下的cmd中输入 tsc
看目录下就会生成一个js文件了
运行Js
05.WebSocket
什么是WebSocket
- 与HTTP协议一样,作用在应用层,是对TCP协议的封装
- 长连接(http大多数情况下是短连接)
安装依赖库
-
初始化工程
npm init
在cmd里打开配置nodeJs的文件夹,还有个简单地方法:直接在文件夹里按住Shift
再右键,点击在此处打开窗口
输完npm init
后会有一些确认信息,如果没问题一直按回车就好。
初始化完会多出来一个文件 -
安装WS库
npm install --save-dev ws
安装完后就会有一个node_moudles文件夹,里面是websocket依赖的所有的库 -
安装WS提示库
npm install @types/ws
提供typescript使用,用来代码提示
全部安装完后就可以使用WebSocket了
使用WebSocket
- 编辑DemoServer文件夹里的ts文件,是服务端
//start.ts
/**创建websocket服务器 */
import * as WebSocket from 'ws';
import * as http from 'http';
/**用来监听端口 */
let ws = new WebSocket.Server({port:8080});
//建立连接之后回调
ws.on('connection',(socket: WebSocket, request: http.IncomingMessage) => {
//ws是类似管理者,只负责监听接口状态
//socket是服务者,是与客户端对接的websocket
console.log("server get connection");
//让服务端给客户端发送一句话
socket.send("hello client, I'm server!");
//收到消息后回调
socket.on("message",(data: WebSocket.Data) => {
console.log("message is receive",data);
})
})
- 再在creator工程里新建一个ts文件,是客户端
/**
*@author Qiu
*@description websocket客户端 连接传数据
*/
const {ccclass, property} = cc._decorator;
@ccclass
export default class WsClient extends cc.Component {
onLoad() {
console.log("client try to connect server");
//cocos自带websocket 直接用
//连接地址:ws:// + 本机ip + 端口号
//为啥要加ws://? 王八的屁股,规定。
let ws = new WebSocket("ws://127.0.0.1:8080");
//客户端和服务器连接上后
ws.onopen = (ev:Event) => {
ws.send("hello,server.I'm client!");
}
//收到消息后回调
ws.onmessage = (ev:Event) => {
console.log("on message",ev);
}
}
}
- 运行服务端,先转js在
node
运行
- 运行客户端,将WsClient.ts加到场景中,在运行到浏览器
诶!有啦
再看看服务端
诶!也有啦
手机连接电脑
- 将客户端连接地址改为电脑私有ip地址
看creator上
let ws = new WebSocket("ws://192.168.18.28:8080");
- 手机扫描creator二维码(手机和电脑要连到同一个局域网)
诶! 有啦有啦
手机也ok啦
06.五子棋–数据UI分层
每节先记下重点,代码最后在放上吧.
做游戏,尤其是网络游戏,要注意逻辑层和UI层要分层
逻辑和数据分开写
初始棋盘上是下满了棋子的,只是隐藏起来,下了哪个就显示哪个,再根据颜色换node显隐。
设计分辨率是750x1334
这样婶滴~
断点后看数据发现有问题:
数组里明明有14个元素,但长度只显示8?
因为数组是从0开始的,而我的数组是从-7到7.
要改成从0开始
数组索引不能出现负数,不然可能会引发问题
07.五子棋–添加玩家
- 五子棋肯定是由两个玩家的
- 给棋子添加点击事件是在棋子节点上加上Button组件,注意:要给节点添加宽高,不然点击不上
- 本节的成果~
08.五子棋–胜负判断
规则:连成五个子就赢了
每下一个子,就判断该子横向/纵向/斜向(四个方向)能不能连成五个或以上
09.服务端匹配
前期准备
- 快速开始NodeJS项目
npm init -y
- 安装项目本地TS
npm install typescript --save-dev
- 安装WS
npm install ws --save-dev
- 安装提示
npm install @types/ws --save-dev
- 生成tsconfig.json
tsc --init
- 安装即时编译
npm install ts-node --save-dev
- 添加nodemon
npm install nodemon --save-dev
详细可看第四节和第五节
可以就直接用之前建的DemoServer,还需要安装本地ts和即时编译还有nodemon
配置入口文件index.ts
index.ts
/**
*@author Qiu
*@description 服务器入口文件
*/
import WebSocket = require ('ws');
import * as http from 'http';
let ws = new WebSocket.Server({port: 8080});
ws.on("connection", (scoket: WebSocket,request: http.IncomingMessage)=>{
console.log("Server get new Connection");
} )
//打印当前时间戳
console.log(`ServerStart ${new Date().getTime()}`);
修改
"script" {
"start" : "npm run build:live",
"build:live" : "nodemon --exec ./node_modules/.bin/ts-node -- ./index.ts"
}
编译文件
在命令行里npm start
就会直接编译start.ts
实时编译的作用就是改变start.js后保存再回到命令行,就会自动检测到改变并再次编译
编写客户端
这里标红了,说没有初始化
是因为ts的配置检查
可以在tsconfig.json里关掉
10.五子棋–网络通信
11.数据库基础
解决数据持久化存储问题
数据库与运行时内存的区别
- 程序运行数据存储在内存,在重启程序时会清空
- 数据库数据存储在硬盘(也有内存型数据库),持久化保存
一个用户登录了一个账号,下次重新登录,账号没了,肯定不行
关系型数据库
介绍
代表: MySQL , Oracle , Microsoft SQL Server
关系模式就是二维表格模型
每个实体之间都有关系
举例
需求:
表格:
学生表:
老师表:
课程表:
优点
- 容易理解,二维表的结构非常贴近现实世界,二维表格,容易理解
- 保持数据的一致性
- 易于维护,大大降低了数据冗余和数据不一致的概率
缺点
- 海量数据的读写效率(需要多表查询,以及硬盘IO)
关系型数据库都是存在硬盘里的,都需要从硬盘里读数据 - 扩展性(加字段,修改表结构)
文档型数据库(非关系型数据库)
介绍
代表: MongoDB , Redis
以键值(Key-Value)来存储,且结构可变,每一个元组(数据)都可以有不一样的字段,这种就不会局限于固定的结构,可以减少一些时间和空间的开销.
使用这种方式,为了获取用户的不同信息,不需要像关系型数据库中,需要进行多表查询.仅仅需要根据Key来取出对应的Value值即可.
举例
优点
- 不定义表结构
- 易于扩展
- 易于数据的分散 把数据分别存储在不同机器里,没问题
- 存储方式: 虚拟内存+持久化
缺点
- 不定义表结构
- 不易维护 (新来的一看,都是些嘛呀!)
- 约束少
总结
- 关系型数据库比较适合类似医院,学校,业务不会经常变化的场景
- 互联网业务比较适合用文档型数据库(本来是个短视频app,诶,往里面加上游戏吧),业务经常变化的
12.MongoDB
安装MongoDB
- 官网下载地址
- 选择"社区服务器",下载
Chrome里打开还可以选择版本和系统,选择msi
安装时就一直"next"
在这个配置页面里可以选择数据和输出存储位置
取消勾选,不然会安装的很慢
再接着"next",直到安装完毕.
来到安装目录里,找到启动程序,双击运行
启动后,可以看到数据库已经运行起来了,而且正在监听端口27017
MongoDB术语介绍
常用命令
-
查看所有数据库
show dbs
-
创建(使用)数据库
use DATABASE_NAME
此时show dbs
并不会显示GoBang库,因为GoBang库里没有数据
-
删除当前数据库
db.dropDatabase()
-
创建集合
db.createCollection(NAME,OPTIONS)
OPTIONS可加选项(一般不会用到):
输入db
可以查看当前操作的数据库
-
显示所有集合
show collections
-
插入文档
db.COLLECTION_NAME.insert(document)
其实document就是json的格式
-
查看文档
db.COLLECTION_NAME.find()
-
更新文档
db.COLLECTION_NAME.update(QUERY,UPDATE,{OPTIONS})
query: update的查询条件,类似sql update查询内where后面的
update: update的对象和一些更新的操作符(如$,$inc) 等,也可以理解为sqlupdate查询内set后面的
upsert: 可选.这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入
multi: 可选.默认是false,只更新找到的第一条记录,如果为true,则把按条件查询出来的文档全部更新
writeConcern: 可选, 抛出异常的级别
- 删除一条:
db.COLLECTION_NAME.deleteOne(QUERY)
- 删除多条:
db.COLLECTION_NAME.deleteMany(QUERY)
13.NodeJs连接数据库
安装NodeJs依赖库
可见04-安装依赖库
就在DemoServer目录里如下安装
安装MongoDB库 npm install mongodb
安装TS提示 npm install @types/mongodb
启动MongoDB服务 mongo --dbpath $YOUR_DB_PATH
mongo是MongoDB目录下的mongod.exe
$YOUR_DB_PATH代表你的MongoDB的安装路径,就是安装目录下的data文件夹
- 新开一个cmd,将MongoDB目录下的bin/mongod.exe拖到cmd中
- 在后面输入
--dbpath
- 再将data文件夹拖进cmd
嗯?有报错
去任务管理器把mongdb进程结束掉,再关掉cmd重新开一个
诶,好了
可以看到数据库正在监听27107端口,
在浏览器访问端口,可以看到数据库的输出
说明服务已经建立起来了
服务器连接数据库
DemoServer/index.ts
/**
*@author Qiu
*@description 服务器入口文件
*/
import WebSocket = require ('ws');
import * as http from 'http';
import Client from './src/Client';
import ClientManager from './src/ClientManager';
import {MongoClient, MongoError } from 'mongodb';
let ws = new WebSocket.Server({port: 8080});
ws.on("connection", (scoket: WebSocket,request: http.IncomingMessage)=>{
console.log("Server get new Connection");
//当有一个客户端连接进来就创建一个客户端类,来保管socket连接
let client = new Client(scoket);
ClientManager.getInstance().addClient(client);
} )
//建立与MongoDB的连接
//相对于MongoDB,服务器就是客户端了
let dburl = "mongodb://localhost:27017";
MongoClient.connect(dburl,(error: MongoError, db: MongoClient)=>{
if (error) {
console.log("Error!",error);
return;
}
console.log("连接数据库成功!")
/**进行查询 */
let goBangDB = db.db("GoBang");
//查询user集合里的所有文档
goBangDB.collection("user").find({}).toArray((error: MongoError, result) => {
if (error) {
console.log("Error!",error);
return;
}
console.log("查询结果:",result);
//用完数据库后记得关掉连接
db.close();
});
});
//打印当前时间戳
console.log(`ServerStart ${new Date().getTime()}`);
启动服务器
14.注册流程-服务端
前期准备
UUID: 基于网卡MAC地址和计时器生成唯一的ID,不会重复
MD5: 根据字符串生成对应的加密串(比如:用户密码123我们需要把它存到数据库里,如果直接存123,如果数据库被攻破了,人家一看都是明文密码,不就完蛋了.所以要加密)
MD5在线破解
安装UUID库
cmd来到DemoServer目录里,也就是服务器目录里
输入npm install uuid
安装UUID提示库
npm install @types/uuid
安装MD5库
npm install ts-md5
机器里本身是自带MD5的
安装后自带安装提示
代码
因为代码各处都会用到数据库,所以最好用单例来重写数据库
单例写的太多了,不想写了,那就弄一个单例基类
/**
*@author Qiu
*@description 单例基类
*/
export default class Singleton<T> {
private static _instance = null;
//c: {new(): T} 代表传进来的参数c有构造函数
public static getInstance<T>(c: {new(): T}): T {
//可以用this是因为该方法也是static
//而且最好使用this,如果用Singleton那所有的单例类都会是同一个_instance
if (this._instance == null) {
this._instance = new c();
}
return this._instance;
}
}
我下的uuid的版本是8.3.2和老师不同,所以老师的版本是
uuid.v1()
,而我的版本是v1()
插一嘴
感觉放在github能更方便看每节的进度,所以试着放到了GitHub上,这样就能看每节都改了哪里.
GitHub链接
有客户端和服务端
查看代码变化
15.注册流程-客户端
点击注册后,会在上方文本显示返回结果
可以在数据库里查到注册的数据
16.登录流程
快捷启动MOngoDB
- 创建一个mongod.exe的快捷方式
- 右键快捷方式,选择属性
将启动的命令行输入到目标里
- 点击确定
- 之后要运行MongoDB直接双击快捷方式就可以了
登录和注册基本上差不多
17.匹配流程
当我们匹配成功后,需要切换场景,但是Gate场景下的WSClient就会随着场景被销毁,那我们想保存的连接就没有了
我们就可以使用cc.game.addPersistRootNode(this.node);
将WSClient节点保存下来,不会随着场景被销毁掉
注意,常驻节点要在场景的根节点下,和Canvas平级
当登录匹配完成,进入main场景,开始下棋
诶,WSClient咋成undefined了?不是常驻了么
监听声明周期后发现,并没有onDestroy,但是有两个onEnable
哦,对了,main场景下也有一个WSClient节点,删掉,OK!
18.断线重连
当游戏中的玩家断开网络时存储棋局数据,当用户重新进入后检查是否有正在进行的棋局,有则拉取数据,继续游戏.
课程结束了,之后会继续把游戏写完,写完就上传到csdn里
更多推荐
零基础学CocosCreator·第八季-双人对战五子棋
发布评论