本文主要描述了在 Cocos2dx 中,使用 Rapidjson
这一Json
解析库在完成网络请求。
🚀 代码: Github
参考资料
网络请求
这一次的作业使用 Cocos2dx 内置的HttpClient
网络库还有rapidjson
JSON 库
引入头文件
首先,我们需要引入对应的头文件
1 |
|
网络请求
下面使一个简单的GET
请求的实现
1 | HttpRequest* request = new HttpRequest(); |
设置好一系列的类型、URL 等参数之后,设置好回调函数,就可以将这个请求加入请求队列中。
然后是回调函数:
1 | void LoginRegisterScene::onHttpRegisterComplete(HttpClient *sender, HttpResponse *response); |
回调函数会在这次请求收到返回值的时候被调用
JSON 的构建
对于大多数的请求,我们都需要提交一个JSON
信息给服务器
这里我们使用rapidjson
来构建 JSON 字符串,将 DOM 形式的数据转换为字符串然后发送给服务器
1 | rapidjson::Document document; |
根据官方文档,对于字符串的创建
RapidJSON
提供两个 String 的存储策略。
copy-string
: 分配缓冲区,然后把来源数据复制至它。const-string
: 简单地储存字符串的指针。
copy-string
总是安全的,因为它拥有数据的克隆。const-string
可用于存储字符串字面量。
由于这里的数据是从对话框中获取的
需要通过StringRef
创建一个copy-string
,然后使用SetString
方法把这个数据传入一个Value
里面,再通过AddMember
添加到Document
中
当然,RapidJSON
还支持很多形式的数据,具体可以查看官方文档
到这里,我们以及获得了一个具有完整数据的DOM
形式的JSON
数据结构,接下就就是要输出,这里使用流来输出。
StringBuffer
是一个简单的输出流。它分配一个内存缓冲区,供写入整个 JSON。
使用 GetString()
来获取该缓冲区,然后添加到网络请求中:
1 | request->setRequestData(buffer.GetString(), buffer.GetSize()); |
JSON 的解析
收到服务器的请求返回之后,就需要解析 JSON 信息了。
1 | std::vector<char> *buffer = response->getResponseData(); |
解析成Document
之后,还需要使用HasParseError
判断是否成功解析,以及是否存在指定的对象,然后才进行下一步的操作。
1 | if (d.HasParseError()) { |
解析 JSON 的大多数方法和C#
中十分类似,这里就不详细说明了。
启用 Cookies
1 | cocos2d::network::HttpClient::getInstance()->enableCookies(nullptr); |
只需要一句话就可以启用 Cookies 了。
Session 的作用
由于 HTTP 是无状态的,因此服务器需要一个手段去识别不同的用户,其中最常用的机制就是Session
。
Session
是存储服务器上的,一般都是存在内存中,一些大型的服务端还会做持久化处理。这个 session 存储着用户的一些状态和信息,比如说是否登陆,用户 ID 等信息。既然说他是存储在服务端的,那么就需要一个方法是匹配客户端和服务端的信息,一般都是使用Cookies
来实现的(这里顺便提一下,为了避免 XSS 攻击,通常会把这个 cookies 设置为httpOnly
,即不能被该网站的脚本查看和修改,只能被浏览器和服务器查看和修改,但是这只是一个协议,对于自己实现协议的客户端并没有约束)。
这个 cookies 的用途就在于跟踪会话,在 cookies 中存储一个唯一的随机字符串,然后在服务端也存储一个类似于哈希表的数据结构,根据这个随机字符串寻找对应会话的信息,就可以使得无状态的 HTTP 实现有状态的会话。对于一些需要用户权限或者数据的请求,可以从 session 中获取用户信息,可以有效阻止非法访问。
遇到的问题
基本上没有遇到什么大问题。
在使用rapidjson
库的时候,由于对这个库不太熟悉,自己去直接尝试传入字符串,发现参数总是不合法,后来查阅了官方文档之后才找到了正确的做法
根据官方文档,对于字符串的创建
RapidJSON
提供两个 String 的存储策略。
copy-string
: 分配缓冲区,然后把来源数据复制至它。const-string
: 简单地储存字符串的指针。
copy-string
总是安全的,因为它拥有数据的克隆。const-string
可用于存储字符串字面量。
由于这里的数据是从对话框中获取的
需要通过StringRef
创建一个copy-string
,然后使用SetString
方法把这个数据传入一个Value
里面,再通过AddMember
添加到Document
中
思考与总结
这次的作业只有网络请求这个,虽然没有什么绚丽的画面,但是在游戏之中是十分重要的,即使是单机游戏有时候也需要联网更新的,对于网络游戏,对于这些请求就更加依赖了。不过对于一些网络游戏,一般都是直接使用 TCP 连接的,这个比 HTTP 连接更加适合于游戏客户端于服务器的连接。如果是一些实时的游戏,可能就需要 UDP 加上自己设计防丢包的协议来实现了(我刚刚用golang
写的一个关于帧同步的游戏服务器就是采用 UDP+队列传输加上回传确认来实现的,性能还是不错的。
回到这次作业上来,这是使用 HTTP 于网络通信,其中比较常用的数据结构就是json
了,大概是它可以和字符串之间轻易地互相转化吧。服务端接收到可以解析成类似于结构体的数据结构,访问就很舒服,服务端也可以返回JSON
给客户端,客户端同样可以解析。然后就达到了传输数据的目的了。
至于 Session 的作用,上面也说的差不多了,要做有用户状态的网络应用,不管是客户端或者是浏览器,这个都是必须的。根据 Session 来辨识用户,显示个性化信息或者用户的私有信息,或者是一些权限操作。
啊,不知道说什么了,就这样吧