本文这是一个在socket中使用protobuf的一个尝试,算是比较简单的尝试。考虑到测试一下跨平台,所以这里是使用NodeJS实现服务端,ObjectC实现客户端,同时也实现了socket链接和数据分隔,protobuf数据类型判断和解析。
Protobuf
源码地址:https://github.com/google/protobuf
Google的一种数据交换的格式,开源的,具有空间开销小、解析速度快、兼容性好等优点,非常适合于对性能要求高的一些场景中。特别是对于即时通讯,就效率和成本而言,二进制协议明显优于http这样的文本协议。
TCP Socket
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。或者理解为:Socket=Ip address+ TCP/UDP + port。
这里用的是tcp协议,主要还是考虑简单的问题,tcp特性就是可靠,有序,为了做到这些,TCP三次握手,每个包有序号,收到会有确认包,还有重传机制,当然还有更多一些机制来保证传输的可靠有序性。
然而在网络差的时候,tcp的优势也会边劣势,这也就是为啥qq是以udp协议为主。如果使用udp,那些需要上层实现来考虑数据的可靠,有序,这需要相当大的工作量,但对于业务的发展、服务器的负载、更多网络环境的适应,udp是非常重要的方向,也是以后探索的一个方向。
NodeJS服务器端实现
NodeJS中Protobuf的第三方模块
常用主要有三种:
protobuf.js : https://github.com/dcodeIO/ProtoBuf.js
Google : https://github.com/google/protobuf/tree/master/js
protocol-buffers : https://github.com/mafintosh/protocol-buffers
这里选用的是protobuf.js。安装全局模块(可以使用命令行工具pbjs):
proto文件
.proto 文件是 Protocol Buffers 的结构化数据定义,结构化数据被称为 Message。
定义一个msg.proto文件
protobuf.js提供了6种方式使用Protobuf,这里使用json的方式,将proto文件编译为一个json文件
编码实现
代码写比较简单,没有实现太多逻辑,特别是socket的管理、断包和粘包的情况并没有处理。
引入protobuf.js库
加载protobuf的数据定义
创建一个socket server的监听
数据解析一、判断类型和去掉分隔符
数据解析二、用protobuf解析数据
发送数据,编码为protobuf的二进制数据,同时拼接类型头和分隔符
ObjectC客户端的实现
安装Protobuf
|
|
可以使用protoc
命令来编译proto文件
Google protobuf/objectivec库
这是官方的protobuf在ObejctC支持库,引用也非常简单,支持cocoapods:
proto文件
直接使用上文的proto文件即可,编译proto文件:
会生成.h
和.m
文件,添加到项目项目中,注意ARC项目的.m
文件要加-fno-objc-arc
编译标记。
CocoaAsyncSocket库
iOS开发中很强大一个socket库,实现了各种类型的socket,还有各种情况的处理,特别是断包粘包的处理,如果想了解更多这个库,建议可以认真看看一个大神写的这5篇博客:一 二 三 四 五
cocoapods 引入:
源码实现
|
|
理解readDataToData:withTimeout:tag:
方法
这个框架每次读取数据,必须手动的去调用上述这些read方法,而我们之前的实现思路是,第一次连接成功的代理触发后调用,之后每次收到消息之后,都在去调用一次这个方法,超时为-1,即不超时。这样我们每次收到消息,都会即时触发我们读取消息的代理。
这里使用读取到指定边界这个方法readDataToData:withTimeout:tag:
,这样CocoaAsyncSocket就帮我们完成断包粘包的问题,同时也实现使用分隔符来识别数据包的问题。分隔符要跟服务器那边统一0x0D
和0x0A
其实它就是一个\r\n
。
protobuf的数据编码和解析也非常简单:
总结一下
Socket对于即时通讯,对于要求即时性高业务是必不可少,而protobuf二进制序列化,虽然相比于json之类的无法肉眼可见可随时编辑,然后它的优点也明显更简洁更快,在一些性能要求高的业务中会是最好的选择。这里技术探索还是比较简单的,特别是socket,udp是一个非常重要的选择,会在以后更多地去接触和学习。