一、项目划分
框架依赖的模块
1.高性能webserver--express模块 热更新 语音对话
2.websocket模块--ws
3.mysql模块-->mysql
4.redis模块-->redis
框架划分
1.webserver作用就是用来上传下载,获取配置信息,更新等.
通过web接入第三方的sdk。
2.gateway网关服务器,
(1)用来接收所有用户的长连接,转发用户请求
(2)连接游戏服务器转发服务器回应
(3)安全防护,过滤非法的数据包隔离游戏服务器免受客户攻击.
3.用户中心服务器: 用来管理这个用户的账号信息.这个用户信息
管理号,可以在进行这个平台的其他游戏.
4.系统服务: 处理用户和系统进行交互:每日登录,邮件,兑换东西等等.
比如你要做一个活动,这个就是用户和服务器单独交互.不会涉及其他用户.
5.游戏服务器:他涉及到多个用户之间的交互,处理不同游戏的服务.
每个服务又是一个进程,
数据库划分
1.后台数据库,分为两个.第一个数据库用来存放用户数据,大家公用的,
第二个是每个游戏都有一个游戏数据库。
2.为了访问速度的提高,把常用的数据缓存到redis服务器,
redis缓冲中心:也是两个:用户redis,和游戏数据redis.
3.数据库是所有进程都公用的.
3rd/utils/netbus模块
1.3rd存放第三方的js代码库
2.utils存放所有的公共模块
3.netbus模块,为所有长连接服务器所公用,支持websocket
TCP socket 二进制和json协议。
二、日志 TCPsocket和websocket模块封装支持
Log日志代码
1.log日志是重要的服务器手段
2.log写日志必须是异步的
3.log日志能够方便的定向到对应的服务器里去
4.log日志分登记和颜色
5.调试时全部打印到标准的输出文件,上线时在输出在文件
6.创建一个output文件夹存放输出的日志.
7.日志分级,如一般信息,警告信息,错误信息.
8.把重要信息保存到log,比如你充值了10元.
验证数据的合法性
1.tcp socket收到的数据必须是Buffer类型
2.ws socket json数据协议下收到的类型必须是字符串
3.ws socket buf数据协议下收到的类型必须是buffer
三、协议管理模块
1.协议规定是: 服务号,命令号,数据部分
2.提供协议解码 cmd[0]服务号,cmd[1]命令号,cmd[2]body三个部分
3.提供协议编码函数转json字符 或者 buff二进制(2字节2字节+body);
4提供协议服务端buf解码器注册函数
5.同时支持json和二进制,通过客户端连接自己选择
6.协议加密和解密也可以加入到这个模块
先编码在加密 —— 先解密在解码
一般只需要支持一种协议即可.
四、netbus服务管理模块
1.当netbus收到数据包的时候,需要把包分发给对应的服务来进行处理
2.service_manager(mg管理)
3.所有服务的管理模块,所有的服务都注册到这里
4.netbus收到数据,玩家掉线等,都进入它,通知对应的服务
5.提供服务模块注册函数,编写模板服务编写
6.转发到对应的服务后,使用decode_cmd 加密命令
7.告诉所有的service链接丢失
五、creator支持websocket_http支持buf和json协议
1.creator使用websocket和服务器进行联机,因为本身creator
本身是h5的,所以
2.ArrayBuffer.DataView,utf8,string字节长度,DataView读/写字符串
ArrayBuffer没有Buffer模块这么多接口,比如readUInt16LE这些.
这个时候就需要借助DataView.

他有一个参数,这个参数是可选的。
如果为 false 或未定义,则写入big-endian(大尾) 值;
否则应写入 little-endia(小尾) 值。
1
2
3
4
5
6
7
|
var buf = new ArrayBuffer(10);
var dataview = new DataView(buf);
dataview.setUint8(0,100);
var value = dataview.getUint8(0);
console.log(value);
|

而DataView只能处理数,没办法处理字符串.需要扩展DataView
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
DataView.prototype.write_utf8 = function (offset,str){
var now = offset;
var dataview = this ;
for ( var i = 0; i < str.length; i++) {
var charcode = str.charCodeAt(i);
if (charcode < 0x80) {
dataview.setUint8(now, charcode);
now ++;
}
else if (charcode < 0x800) {
dataview.setUint8(now, (0xc0 | (charcode >> 6)));
now ++;
dataview.setUint8(now, 0x80 | (charcode & 0x3f));
now ++;
}
else if (charcode < 0xd800 || charcode >= 0xe000) {
dataview.setUint8(now, 0xe0 | (charcode >> 12));
now ++;
dataview.setUint8(now, 0x80 | ((charcode>>6) & 0x3f));
now ++;
dataview.setUint8(now, 0x80 | (charcode & 0x3f));
now ++;
}
else {
i ++;
charcode = 0x10000 + (((charcode & 0x3ff)<<10)
| (str.charCodeAt(i) & 0x3ff));
dataview.setUint8(now, 0xf0 | (charcode >>18));
now ++;
dataview.setUint8(now, 0x80 | ((charcode>>12) & 0x3f));
now ++;
dataview.setUint8(now, 0x80 | ((charcode>>6) & 0x3f));
now ++;
dataview.setUint8(now, 0x80 | (charcode & 0x3f));
now ++;
}
}
}
DataView.prototype.read_utf8 = function (offset,byte_length){
var out,i,len,c;
var char2,char3;
var dataview = this ;
out = "" ;
len = byte_length;
i = offset;
while (i < len){
c = dataview.getUint8(i);
i++;
switch (c >> 4)
{
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
out += String.fromCharCode(i);
break ;
case 12: case 13:
char2 = array[i++];
out += String.fromCharCode(((c & 0x1F)<<6) | (char2 & 0x3F));
break ;
case 14:
char2 = dataview.getUint8(i);
i++;
char3 = dataview.getUint8(i);
i++;
out += String.fromCharCode(((c & 0x0F)<<12)|
((char2 & 0x3F) << 6) |
((char3 & 0x3F) << 0));
break ;
}
}
}
|
封装websocket模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
var proto = require( "proto_mgr" );
console.log( "proto:" ,proto);
var websocket = {
sock: null ,
serivces_handler: null ,
proto_type: 0,
is_commected: false ,
_on_opened: function (event){
console.log( "ws connect server success!" );
this .is_commected = true ;
},
_on_recv_data: function (strbufdata){
if (! this .serivces_handler){
console.log( "not find serivces_handler" );
return ;
}
var cmd = proto.decode_cmd( this .proto_type,strbufdata);
if (!cmd){
console.log( "websocket.js(25) cmd invaild!" );
return ;
}
var stype = cmd[0];
if ( this .serivces_handler[stype]){
this .serivces_handler[stype](cmd[0],cmd[1],cmd[2]);
}
},
_on_socket_close: function (event){
if ( this .sock){
this .close();
}
},
_on_socket_err: function (event){
this .close();
},
connect: function (url,proto_type){
this .sock = new WebSocket(url);
this .sock.onopen = this ._on_opened.bind( this );
this .sock.onmessage = this ._on_recv_data.bind( this );
this .sock.onclose = this ._on_socket_close.bind( this );
this .sock.onerror = this ._on_socket_err.bind( this );
this .proto_type = proto_type;
},
send_cmd: function (stype,ctype,body){
if (! this .sock || ! this .is_commected){
console.log( "send commind error!" );
return ;
}
var buf = proto.encode_cmd( this .proto_type,stype,ctype,body);
this .sock.send(buf);
},
close: function (){
this .is_commected = false ;
if ( this .sock !== null ){
this .sock.close();
this .sock = null ;
}
},
regist_services_handler: function (serivces_handler){
this .serivces_handler = serivces_handler;
},
}
module.exports = websocket;
|
封装http模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
var http = {
get: function (url, path, params,callback){
var xhr = cc.loader.getXMLHttpRequest();
xhr.timeout = 5000;
var requestURL = url + path;
if (params){
requestURL = requestURL + "?" + params;
}
xhr.open( "GET" ,requestURL, true );
if (cc.sys.isNative){
xhr.setRequestHeader( "Accept-Encoding" , "gzip,deflate" , "text/html;charset=UTF-8" );
}
xhr.onreadystatechange = function (){
if (xhr.readyState === 4 && (xhr.status >= 200 && xhr.status < 300)){
console.log( "http res(" +xhr.responseText.length+ "):" +xhr.responseText);
try {
var ret = xhr.responseText;
if (callback !== null ){
callback( null ,ret);
}
return ;
} catch (e){
callback(e, null );
}
}
else {
callback(xhr.readyState+ ":" +xhr.status, null );
}
};
xhr.send();
return xhr;
},
post: function (url,path,params,body,callback){
var xhr = cc.loader.getXMLHttpRequest();
xhr.timeout = 5000;
var requestURL = url + path;
if (params){
requestURL = requestURL + "?" + params;
}
xhr.open( "POST" ,requestURL, true );
if (cc.sys.isNative){
xhr.setRequestHeader( "Accept-Encoding" , "gzip,deflate" , "text/html;charset=UTF-8" );
}
if (body){
xhr.setRequestHeader( "Content-Type" , "application/x-www-form=urlencoded" );
xhr.setRequestHeader( "Content-Length" ,body.length);
}
xhr.onreadystatechange = function (){
if (xhr.readyState === 4 && (xhr.status >= 200 && xhr.status < 300)){
try {
var ret = xhr.responseText;
if (callback !== null ){
callback( null ,ret);
}
return ;
} catch (e){
callback(e, null );
}
}
else {
callback(xhr.readyState+ ":" +xhr.status, null );
}
};
if (body){
xhr.sned(body);
}
return xhr;
},
download: function (url,path,params,callback){
var xhr = cc.loader.getXMLHttpRequest();
xhr.timeout = 5000;
var requestURL = url + path;
if (params){
requestURL = requestURL + "?" + params;
}
xhr.responseType = "arraybuffer" ;
xhr.open( "GET" ,requestURL, true );
if (cc.sys.isNative){
xhr.setRequestHeader( "Accept-Encoding" , "gzip,deflate" , "text/html;charset=UTF-8" );
}
xhr.onreadystatechange = function (){
if (xhr.readyState === 4 && (xhr.status >= 200 && xhr.status < 300)){
var buffer = xhr.response;
var dataview = new DataView(buffer);
var ints = new Uint8Array(buffer.byteLength);
for ( var i = 0;i < ints.length; i++){
ints[i] = dataview.getUint8(i);
}
callback( null ,ints);
} else {
callback(xhr.readyState+ ":" +xhr.status, null );
}
};
xhr.send();
return xhr;
},
};
module.exports = http;
|
本文转自超级极客51CTO博客,原文链接:http://blog.51cto.com/12158490/2071208,如需转载请自行联系原作者