参考文章:开发小游戏(服务端开发看)
参考文章《外部域名添加》的开通云服务和添加章节。
参考文章:创建与信息完善
参考文章的第一章。
将域名igo-open-demo.taobao.com配置到后台上,下文会用到;
选择对应的项目,然后选择设置项目保存路径,点击【确定】。
测试服务器(仅做演示用):
wss://igo-open-demo.taobao.com/websocket/test
代码:
const websocketTest = () => {
const socketTask = my.connectSocket({
url: 'wss://igo-open-demo.taobao.com/websocket/test', // 开发者服务器接口地址,必须是 wss 协议
multiple: true // 多连接模式,才会返回 SocketTask
, success: (res) => {
console.log('WebSocket open success', res);
}, fail: (err) => {
// 如果这里出错了,就要去执行兜底逻辑,比如重新连接
console.error('WebSocket open error', err);
}
});
socketTask.onOpen(res => {
console.log(`WebSocket 已连接,socketTaskID = ${res.data.socketTaskID}`);
socketTask.send({
data: 'hi'
});
// SocketTask 目前支持多连接。而 my.connectSocket 不支持多连接,所以建议使用SocketTask。
const second = my.connectSocket({
url: 'wss://igo-open-demo.taobao.com/websocket/test', // 开发者服务器接口地址,必须是 wss 协议
multiple: true // 多连接模式,才会返回 SocketTask
, success: (res) => {
console.log('WebSocket open success', res);
}, fail: (err) => {
// 如果这里出错了,就要去执行兜底逻辑,比如重新连接
console.error('WebSocket open error', err);
}
});
second.onOpen(res => {
console.log(`WebSocket 已连接,socketTaskID = ${res.data.socketTaskID}`);
try {
const base64 = utils.arrayBufferToBase64(new Uint8Array([11, 22, 33]).buffer);
console.log('base64', base64);
second.send({
data: base64,
isBuffer: true, // 标记为二进制数据
success: (res) => {
console.log('second.send success', res);
},
fail: (err) => {
console.error('second.send error', err);
},
complete: (res) => {
console.log('second.send complete', res);
}
});
} catch (error) {
console.log('onOpen Error:', error);
}
});
second.onMessage((res) => {
console.log('second.onMessage 接收到了消息', res.data, res?.data?.isBuffer);
try {
if (res?.data?.isBuffer) { // 判断是否为二进制数据
const arrayBuffer = utils.base64ToArrayBuffer(res.data?.data);
console.log('receive arrayBuffer:', arrayBuffer);
my.alert({ content: new Uint8Array(arrayBuffer || []).toString(), title: 'second 收到' });
}
} catch (error) {
console.error('second onMessage Error:', error);
}
});
});
socketTask.onClose((res) => {
console.log('WebSocket.onClose 连接已关闭!', res);
});
socketTask.onError((res) => {
console.log('WebSocket.onError 连接失败!', res);
});
socketTask.onMessage((res) => {
console.log('WebSocket.onMessage 接收到了消息', res.data);
});
}
在game.js的代码尾部调用测试函数
websocketTest();
点击构建日志可以查看构建日志
设置权限:设置成员
查看【真机调试】日志
目前淘宝小游戏的http协议不支持二进制数据传输,仅支持字符串发送。所以在例子中将二进制数据转化base64后发送。同时后端发送过来的数据也会被转化成字符串数据,前端也将其解码成二进制数据;注意发送二进制数据要将isBuffer设置为true,在解析的时候判断isBuffer为真则进行二进制转换;
utils.js请查看附录。
二进制转化为base64
const base64 = utils.arrayBufferToBase64(new Uint8Array([11, 22, 33]).buffer);
console.log('base64', base64);
second.send({
data: base64,
isBuffer: true, // 标记为二进制数据
success: (res) => {
console.log('second.send success', res);
},
fail: (err) => {
console.error('second.send error', err);
},
complete: (res) => {
console.log('second.send complete', res);
}
});
base64转化为二进制
second.onMessage((res) => {
console.log('second.onMessage 接收到了消息', res.data, res?.data?.isBuffer);
try {
if (res?.data?.isBuffer) { // 判断是否为二进制数据
const arrayBuffer = utils.base64ToArrayBuffer(res.data?.data);
console.log('receive arrayBuffer:', arrayBuffer);
my.alert({ content: new Uint8Array(arrayBuffer || []).toString(), title: 'second 收到' });
}
} catch (error) {
console.error('second onMessage Error:', error);
}
});
部分游戏有建立多个websocket通讯的需求,SocketTask 目前支持多连接,老接口 my.connectSocket 不支持多连接,请注意区别使用。
使用cocos引擎进行websocket通讯,不需要考虑二进制和字符串互转的问题,cocos引擎部分版本支持多连接,请参考下表:
引擎大版本 |
支持版本 |
2.x |
待发布,具体参考cocos的发版说明;若急用请在GitHub下载cocos 2.4.15 的websocket代码; |
3.x |
v3.8.4 |
使用laya引擎进行websocket通讯,不需要考虑二进制和字符串互转的问题,同时laya引擎也支持多连接。
const utils = {
/**
* @param {Object} target
* @param {Object} origin
* @param {String} methodName
* @param {String} targetMethodName
*/
cloneMethod (target, origin, methodName, targetMethodName) {
if (origin[methodName]) {
targetMethodName = targetMethodName || methodName;
target[targetMethodName] = origin[methodName].bind(origin);
}
},
/**
*
* @param {String} str
* @returns
*/
encode (str) {
let encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const string = String(str);
let result = '';
let currentIndex = 0;
let sum = void 0;
while (string.charAt(0 | currentIndex) || (encodings = '=', currentIndex % 1)) {
currentIndex += 0.75;
const currentCode = string.charCodeAt(currentIndex);
if (currentCode > 255) {
// Cannot handle when it is greater than 255
throw new Error('"btoa" failed');
}
sum = sum << 8 | currentCode;
const encodeIndex = 63 & sum >> 8 - currentIndex % 1 * 8;
result += encodings.charAt(encodeIndex);
}
return result;
},
/**
*
* @param {String} str
*/
decode (str) {
const encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
let res = '';
const string = String(str).replace(/[=]+$/, '');
let o;
let r;
let i = 0;
let currentIndex = 0;
while (r = string.charAt(currentIndex)) {
currentIndex += 1;
r = encodings.indexOf(r);
if (~r) {
o = i % 4 ? 64 * o + r : r;
if (i++ % 4) {
res += String.fromCharCode(255 & o >> (-2 * i & 6));
}
}
}
return res;
},
/**
*
* @param {ArrayBuffer} buffer
*/
arrayBufferToBase64 (buffer) {
return utils.encode(utils.arrayBufferToString(buffer));
},
/**
*
* @param {String} base64
*/
base64ToArrayBuffer (base64) {
return utils.stringToArrayBuffer(utils.decode(base64));
},
/**
*
* @param {ArrayBuffer} buffer
*/
arrayBufferToString (buffer) {
let result = '';
const uintArray = new Uint8Array(buffer);
const byteLength = uintArray.byteLength;
for (let i = 0; i < byteLength; i++) {
result += String.fromCharCode(uintArray[i]);
}
return result;
},
/**
*
* @param {String} string
*/
stringToArrayBuffer (string) {
const length = string.length;
const uintArray = new Uint8Array(length);
for (let i = 0; i < length; i++) {
uintArray[i] = string.charCodeAt(i);
}
return uintArray.buffer;
},
};
module.exports = utils;