最近一直在研究微信小程序。
到今天刚刚把客户端完成了,这个客户端应当可以满足对数据要求不是特别多的tcpsocket请求和处理。
朋友们如果需要使用TCPSOCKET与服务器交换数据的,可以把下面代码直接拷贝使用。只要你的数据量不是很大,都可以满足。
只有小程序客户端的代码,服务器是用JAVA写的,就不上了(以前写的,比较庞大,上百万行代码)
其中的arraybufferTOString和stringTOArrayBuffer,参考了其他朋友的代码。
至于其他页面发送的服务器数据请求使用的代码,很简单,就是一个JSON数据结构,服务器返回的数据也是JSON结构,处理起来比较简单。
getApp().globalData.coma.push(
{ id:50,
name:"手机号码验证",
value:this.data.phone.trim(),
thisEvent:this
},
);
上代码
// app.js
App({
onLaunch() {
// 展示本地存储能力
const logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now())
wx.setStorageSync('logs', logs)
//this.globalData.registerStatus=wx.getStorageSync('registerStatus')
if (!this.globalData.registerStatus){
wx.removeStorageSync('appcode')
wx.removeStorageSync('userid')
wx.removeStorageSync('phone')
wx.removeStorageSync('firstlogintime')
wx.removeStorageSync('registerStatus')
}
this.globalData.appcode = wx.getStorageSync('appcode')//用来对数据进行加密
this.globalData.firstlogintime = wx.getStorageSync('firstlogintime')//用来对数据进行加密
this.globalData.userid = wx.getStorageSync('userid')
this.globalData.phone = wx.getStorageSync('phone')
this.startMsgDel()
this.initapp();
},
globalData: {
registerStatus:false,
userInfo: null,
phone:'',
isConnected:false,
socketTask:null,
serverHostname:'192.168.1.5',
serverPort:8189,
appcode:'',
firstlogintime:0,
commtype:0,
componentsMap:new Map(),//存储所有组件的信息
msga:new Array(),//从服务器接收到的数据
coma:new Array(), //客户端发出的命令
resulta:new Array(), //处理以后的命令等待队列
sendmessage:new Array(),//需要发送到服务器的命令以及数据
waiting_result_command:new Map(),//the command is sent to the sever and waiting result
userid:0,//用户 id on the server
phonecheck:false,
result:null,
heartbeatInterval:null,
iswaiting:false,
},
initapp:function(){
wx.login({
success: (res) => {
if (res.code){
this.globalData.appcode = res.code;
this.globalData.coma.push(
{ id:this.globalData.registerStatus ? 2 : 1,
name:this.globalData.registerStatus ? '检查注册信息' : '获取Openid',
value:res.code,
thisEvent:this.globalData,
},
);
}
},
})
},
connectToServer:function(){
if (this.globalData.socketTask == null){
this.globalData.socketTask = wx.createTCPSocket();
}
this.globalData.isConnected = false;
let that = this;
this.globalData.socketTask.offConnect();
this.globalData.socketTask.onConnect(() => {
that.globalData.isConnected = true;
that.globalData.iswaiting = false;
});
this.globalData.socketTask.offError();
this.globalData.socketTask.onError((res) => {
that.globalData.isConnected = false;
});
this.globalData.socketTask.offClose();
this.globalData.socketTask.onClose((res) =>{
that.globalData.isConnected = false;
});
this.globalData.socketTask.offMessage();
this.globalData.socketTask.onMessage(function(e){
that.globalData.msga.push(e.message);
});
this.globalData.socketTask.connect({address:this.globalData.serverHostname,port:this.globalData.serverPort});
},
startMsgDel:function(){
let that = this;
this.globalData.heartbeatInterval = setInterval(() => {
that.msgDel();//处理 tcpsocket 接收到的新数据
that.comDel();//处理客户端发出的各种命令
that.sendMessageTOServer();//发送数据到服务器
that.dealing_result();//处理服务器返回的数据
}, 500);//每秒执行2次
},
msgDel:function(){
if (this.globalData.msga.length == 0) return;
var ab = this.globalData.msga.shift();
if (ab.byteLength == 4){//服务器第一次连接的时候返回4个字节
var dataview = new DataView(ab);
if (dataview.getInt32() != 827212108) {
this.globalData.socketTask.close();
}
return;
}
var js = JSON.parse(this.arrayBufferToString(ab));
this.globalData.resulta.push(js);
},
comDel:function(){
if (this.globalData.coma.length == 0) return;
var jb = this.globalData.coma.shift();
var cb = null;
this.globalData.waiting_result_command.set(jb.id,jb);
cb = this.stringToArrayBuffer(jb.value,jb.id);
this.globalData.sendmessage.push(cb);
},
//发送命令和数据到服务器
sendMessageTOServer:function(){
if (this.globalData.sendmessage.length == 0) return;
if (!this.globalData.isConnected){
if (!this.globalData.iswaiting){
this.globalData.iswaiting = true;
this.connectToServer();
}
return;
}
var sm = this.globalData.sendmessage.shift();
if (this.globalData.isConnected){
console.log('send message to server')
this.globalData.socketTask.write(sm);
}
},
//dealing the result
dealing_result:function(){
if (this.globalData.resulta.length == 0) return;
var rsa = this.globalData.resulta.shift();
var sourcec = this.globalData.waiting_result_command.get(rsa.commn).thisEvent
if (sourcec == null){
wx.showModal({
title: '错误提示',
content: '接收到错误的数据',
showCancel:false,
complete: (res) => {
if (res.confirm) {
}
}
})
return;
}else{
this.globalData.waiting_result_command.delete(rsa.commn)
}
console.log(rsa);
switch (rsa.commn){
case 1:
try{
switch (parseInt(rsa.status)){
case 0:
console.log(sourcec)
sourcec.userid = rsa.userid
sourcec.firstlogintime =rsa.firstlogintime
wx.setStorageSync('appcode', sourcec.appcode);
wx.setStorageSync('firstlogintime', sourcec.firstlogintime)
wx.setStorageSync('registerStatus', rsa.registerStatus == 0 ? sourcec.registerStatus = true : sourcec.registerStatus = false);
wx.setStorageSync('phone', rsa.registerStatus == 0 ? sourcec.phone = rsa.phone : sourcec.phone = '')
wx.setStorageSync('userid',ras.userid)
sourcec.registerStatus = wx.getStorageSync('registerStatus');
console.log(sourcec)
break;
default:
wx.showModal({
title: '错误提示',
content: '出现未知错误...,请稍后重试',
showCancel:false,
complete: (res) => {
if (res.confirm) {
}
}
})
}
}catch(e){
}
break;
case 2:
try{
switch (parseInt(rsa.status)){
case 0:
sourcec.userid = rsa.userid
wx.setStorageSync('appcode', sourcec.appcode);
wx.setStorageSync('firstlogintime', sourcec.firstlogintime)
wx.setStorageSync('registerStatus', rsa.registerStatus == 0 ? sourcec.registerStatus = true : sourcec.registerStatus = false);
wx.setStorageSync('phone', rsa.registerStatus == 0 ? sourcec.phone : sourcec.phone = '')
wx.setStorageSync('userid',rsa.userid)
console.log(sourcec)
break;
case 1:
break;
default:
wx.showModal({
title: '错误提示',
content: '出现未知错误...,请稍后重试',
showCancel:false,
complete: (res) => {
if (res.confirm) {
}
}
})
}
}catch(e){
}
break;
case 50://手机发送短信验证码
switch (parseInt(rsa.status)){
case 0://成功发送验证码
sourcec.dataSet({
display_button:true,
dispt:true,
})
break;
case 1://发送验证码错误
sourcec.dataSet({
display_button:false,
dispt:true,
})
wx.showModal({
title: '错误',
content: '请稍后再尝试...',
showCancel:false,
complete: (res) => {
if (res.confirm) {
}
}
})
break;
case 2://不能频繁发送验证码
sourcec.dataSet({
display_button:false,
dispt:true,
})
wx.showModal({
title: '发送过于频繁',
content: '一分钟只能发送一次',
showCancel:false,
complete: (res) => {
if (res.confirm) {
}
}
})
break;
case 3://验证码发送服务器返回错误
sourcec.dataSet({
display_button:false,
dispt:true,
})
wx.showModal({
title: '服务器提示错误',
content: '服务器提示错误,请稍后再尝试...',
showCancel:false,
complete: (res) => {
if (res.confirm) {
}
}
})
break;
}
break;
case 51://手机号码注册
switch (parseInt(rsa.status)){
case 0://成功注册手机号码
sourcec.dataSet({
display_button:false,
dispt:false,
})
this.globalData.registerStatus = true;
this.globalData.userid = rsa.userid;
this.globalData.phone = rsa.phone;
wx.setStorageSync('registerStatus', true);
wx.setStorageSync('phone', this.globalData.phone);
wx.setStorageSync('userid', this.globalData.userid);
this.globalData.componentsMap.get('tabs').dataSet(
{
phone:this.globalData.phone,
}
)
}
break;
}
},
//str is the value,
//cn is the id(command number)
stringToArrayBuffer: function(str,cn) {
if (typeof str === 'string'){
}else
return null;
var bytes = new Array();
var len,c;
len = str.length;
for(var i = 0; i < len; i++){
c = str.charCodeAt(i);
if(c >= 0x010000 && c <= 0x10FFFF){
bytes.push(((c >> 18) & 0x07) | 0xF0);
bytes.push(((c >> 12) & 0x3F) | 0x80);
bytes.push(((c >> 6) & 0x3F) | 0x80);
bytes.push((c & 0x3F) | 0x80);
}else if(c >= 0x000800 && c <= 0x00FFFF){
bytes.push(((c >> 12) & 0x0F) | 0xE0);
bytes.push(((c >> 6) & 0x3F) | 0x80);
bytes.push((c & 0x3F) | 0x80);
}else if(c >= 0x000080 && c <= 0x0007FF){
bytes.push(((c >> 6) & 0x1F) | 0xC0);
bytes.push((c & 0x3F) | 0x80);
}else{
bytes.push(c & 0xFF);
}
}
//32 bytes are the package header
let ab = new Int8Array(36 + bytes.length);
for(var i = 0 ;i <= bytes.length;i++){
ab[i + 36] =bytes[i];
}
let db = new DataView(ab.buffer);
db.setUint32(0,1229015365);//this is the handover
db.setUint32(4,1312902227);//the low bytes
db.setUint32(8,4);//4 is the type of the device,0-3 is the desktop,4 is phone
db.setBigInt64(12,BigInt(this.globalData.userid));//userid
db.setUint32(24,4 + bytes.length);//length
db.setUint32(32,cn);//command number
return db.buffer;
},
arrayBufferToString:function(arr){
var dataview=new DataView(arr);
var ints=new Uint8Array(arr.byteLength);
for(var i=0;i<ints.length;i++){
ints[i]=dataview.getUint8(i);
}
arr=ints;
var str = '',
_arr = arr;
for(var i = 0; i < _arr.length; i++) {
var one = _arr[i].toString(2),
v = one.match(/^1+?(?=0)/);
if(v && one.length == 8) {
var bytesLength = v[0].length;
var store = _arr[i].toString(2).slice(7 - bytesLength);
for(var st = 1; st < bytesLength; st++) {
store += _arr[st + i].toString(2).slice(2);
}
str += String.fromCharCode(parseInt(store, 2));
i += bytesLength - 1;
} else {
str += String.fromCharCode(_arr[i]);
}
}
return str;
},
})