├── README.md ├── bin └── mqttSocketIoPhp.js ├── im-ldev-restart.sh ├── im-server-restart.sh ├── im-server.sh ├── lib ├── cookie.js ├── createMqttServer.js ├── mqttSocketIoPhp.js ├── mqttSocketIoPhp.js.bak └── session_decode.js ├── package.json └── test └── mqttSocketIoPhp.js /README.md: -------------------------------------------------------------------------------- 1 | mqtt-socketIo-php 2 | ================= 3 | 4 | 用 nodejs ,php ,mqtt 实现的IM聊天系统,实现了 1: 点对点聊天和群聊 。2:实现了PC和移动设备的通信。(android的代码暂未提供)。 5 | -------------------------------------------------------------------------------- /bin/mqttSocketIoPhp.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var mqttSocketIophp = require("../lib/mqttSocketIoPhp"); 3 | console.log('success'); 4 | 5 | -------------------------------------------------------------------------------- /im-ldev-restart.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | kill `ps aux | grep mqttSocketIoPhp.js | grep -v grep | awk -F' ' '{print $2}'` 3 | echo 'killed' 4 | 5 | node ./lib/mqttSocketIoPhp.js 6 | 7 | 8 | -------------------------------------------------------------------------------- /im-server-restart.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | kill `ps aux | grep mqttSocketIoPhp.js | grep -v grep | awk -F' ' '{print $2}'` 3 | echo 'killed' 4 | 5 | nohup node mqttSocketIoPhp.js >> node_output.log & 6 | 7 | 8 | -------------------------------------------------------------------------------- /im-server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #node server 3 | 4 | DATE=$(date '+%m%d%y') 5 | date_log=node_output_$DATE.log # log 6 | while [ true ] 7 | do 8 | nohup node ./lib/mqttSocketIoPhp.js 2>> $date_log 9 | done 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /lib/cookie.js: -------------------------------------------------------------------------------- 1 | //Directly send cookie to system, if it's node.js handler, send : 2 | //request.headers.cookie 3 | //If it's socket.io cookie, send : 4 | //client.request.headers.cookie 5 | module.exports.cookie = function(co){ 6 | this.cookies = {}; 7 | co && co.split(';').forEach(function(cookie){ 8 | var parts = cookie.split('='); 9 | this.cookies[parts[0].trim()] = (parts[1] || '').trim(); 10 | }.bind(this)); 11 | 12 | //Retrieve all cookies available 13 | this.list = function(){ 14 | return this.cookies; 15 | }; 16 | 17 | //Retrieve a key/value pair 18 | this.get = function(key){ 19 | if(this.cookies[key]){ 20 | return this.cookies[key]; 21 | }else{ 22 | return {}; 23 | } 24 | }; 25 | 26 | //Retrieve a list of key/value pair 27 | this.getList = function(map){ 28 | var cookieRet = {}; 29 | for(var i=0; i -1) { 48 | this.splice(index, 1); 49 | } 50 | }; 51 | 52 | Array.prototype.in_array = function (e) { 53 | for (i = 0; i < this.length && this[i] != e; i++); 54 | return !(i == this.length); 55 | } 56 | 57 | 58 | var util = require('util'); 59 | var client = mqtt.connect();; 60 | //MQTTClient(1883, '127.0.0.1', 'pusher'); 61 | global.io = require('socket.io'); 62 | var Memcached = require('memcached'); 63 | var memcached = new Memcached('localhost:11211'); 64 | //var PHPUnserialize = require('php-unserialize'); 65 | //var sessionecode = require('./session_decode.js'); 66 | server = http.createServer(function (req, res) { 67 | res.writeHead(200, {'Content-Type': 'text/plain'}); 68 | res.end('node shell\n'); 69 | }); 70 | server.listen(5000); 71 | io = io.listen(server); 72 | var createMqttServer = require('./createMqttServer.js'); 73 | var roomOnlineNum = new Array(); 74 | var obj = {}; 75 | var onlineUsersId = new Array(); //在线用户Id的数组。以能够准确判定当前在线人数。 76 | var socketMap = {}; 77 | //var roomUserToUser = 'userTouser-'; 78 | var userClients = new Array(); 79 | var msg = ''; 80 | var portrait = ''; 81 | var mqttContent = ''; 82 | var sql = ''; 83 | var roomActivity = 'activity-'; 84 | var roomClub = 'club-'; 85 | var roomUsersGroup = 'group-'; 86 | var roomUserToUser = 'userTouser-'; 87 | var socketArr = new Array(); 88 | var new_data = new Array(); 89 | /** 90 | * 过滤特殊字符 91 | * @param s 92 | * @returns {String} 93 | */ 94 | function stripscript(s) { 95 | var pattern = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\].<>/?~!@#¥……&*()——|{}【】‘;:”“'。,、?]") 96 | var rs = ""; 97 | for (var i = 0; i < s.length; i++) { 98 | rs = rs + s.substr(i, 1).replace(pattern, ''); 99 | } 100 | return rs; 101 | } 102 | 103 | 104 | //下步两项任务: 105 | // 1: 将用户所有的clientID记录进入memcached,并实现用户离线的自身的socket的清理断开。 106 | // 2: 查询当前socket用户的所有好友userId,并查询出都那些人在线。 107 | // 3: 查询当前socket用户加入的所有俱乐部的clubId,并统计在线人数。 108 | // 4: 查询当前socket用户加入的活动的activityId,并统计在线人数。 109 | 110 | //memcached.get('1g8n9qneetpiapup2utdf9qm12_userId', function (err, data) { 111 | // console.log('session jin ru 111'); 112 | // console.dir( data ); 113 | // console.log('session tui chu 222'); 114 | //}); 115 | 116 | io.sockets.on('connection', function (socket) { 117 | var topic = ''; 118 | 119 | console.log('io.clients'); 120 | console.log(io.clients); 121 | console.log('io.clients'); 122 | console.log('io-----------------------------------------'); 123 | console.log(io); 124 | console.log('io-----------------------------------------'); 125 | for (sessionId in io.clients) { 126 | io.clients[sessionId].send(JSON.stringify(update)); 127 | } 128 | 129 | 130 | socket.on('subscribe', function (data) { 131 | var count = 1; 132 | socket.topic = data.topic; 133 | socket.payload = data.payload; 134 | room = data.topic; 135 | userInfo = JSON.parse(data.payload); 136 | phpsession = userInfo.phpsession + '_userId'; 137 | //生成socketId与userId的键值对: (key=>value) 如: socketId => userId 138 | socketArr[socket.id] = userInfo.userId; 139 | console.log('socketArr'); 140 | console.log(socketArr); 141 | console.log('socketArr'); 142 | //用户只要登录就订阅所有的消息。 143 | //1:首先订阅个人信息 144 | socketMap[roomUserToUser + userInfo.userId] = socket; 145 | //订阅俱乐部/活动/讨论组的信息。 146 | sql = "select activityId from ActivityUserInvitation where inviteeUserId= " + connection.escape(userInfo.userId); 147 | connection.query(sql, function (err, results) { 148 | for (i = 0; i < results.length; i++) { 149 | socket.join(roomActivity + results[i].activityId); 150 | } 151 | }); 152 | sql = "select kuulabuId from KuulabuUser where userId= " + connection.escape(userInfo.userId); 153 | connection.query(sql, function (err, results) { 154 | for (i = 0; i < results.length; i++) { 155 | socket.join(roomClub + results[i].kuulabuId); 156 | } 157 | }); 158 | 159 | console.log('clientId:' + socket.id); 160 | var userClientArr = new Array(); 161 | //查询当前socket用户的clients信息,并进行绑定 162 | memcached.get(userInfo.userId, function (err, result) { 163 | if (result) { 164 | result = new String(result); //强制转换为字符串类型,因为memcached获取的结果是object 165 | data = result.split(","); 166 | console.log('testtest-----test-----'); 167 | for (i = 0; i < data.length; i++) { 168 | console.log("data " + i + ":" + data[i]); 169 | } 170 | console.log('testtest-----test-----'); 171 | if (!data.in_array(socket.id)) { 172 | data.push(socket.id); 173 | userClients = data.join(","); 174 | console.log("userClients:" + userClients); 175 | memcached.set(userInfo.userId, userClients, 10000, function (err, result) { 176 | if (err) console.error(err); 177 | console.dir(result); //返回值为boolen值 178 | console.log('stop aaaaa==========================='); 179 | }); 180 | } 181 | } else { 182 | userClientArr.push(socket.id); 183 | userClients = userClientArr.join(","); 184 | memcached.set(userInfo.userId, userClients, 10000, function (err, result) { 185 | if (err) console.error(err); 186 | console.dir(result); //返回值为boolen值 187 | }); 188 | console.log('data start '); 189 | console.log(data); 190 | console.log('data end! '); 191 | } 192 | }); 193 | //查看当前好友的在线信息。 194 | sql = "select friendUserId from UserFriend where isAuthorized=1 and userId = " + connection.escape(userInfo.userId); 195 | connection.query(sql, function (err, results) { 196 | for (i = 0; i < results.length; i++) { 197 | //通知自己的好友自己已经上线 198 | roomMyFriends = roomUserToUser + results[i].friendUserId; 199 | if (socketMap.hasOwnProperty(roomMyFriends)) { 200 | console.log('点对点有值' + results[i].friendUserId); 201 | socketFriend = socketMap[roomMyFriends]; 202 | //主动发送消息 203 | socketFriend.emit('online', {'topic': roomMyFriends, 204 | 'room': roomMyFriends, 205 | 'payload': String(userInfo.userId)}); 206 | } 207 | } 208 | }); 209 | 210 | 211 | //将在线好友的列表发送到客户端。 212 | 213 | //及时将自己的登录状况发送给自己的好友。 214 | //处理群(活动,俱乐部)的好友的在线状态。 215 | //及时将自己的登录发送给自己相关的群。 216 | 217 | 218 | // socket.join(data.topic); 219 | client.subscribe(data.topic); //向特定的用户发送信息。 220 | //向用户推送用户未读的信息。 221 | userTouserNonReadMessageSql = 'select u.userId,u.defaultNickname,ut.message,ut.createTime ' + 222 | 'from UserTouserChatRecord ut ,User u ' + 223 | 'where ut.accepterUserId= ' + connection.escape(userInfo.userId) + ' and ut.isRead=0 and u.userId=ut.senderUserId '; 224 | console.log('userTouserNonReadMessageSql:' + userTouserNonReadMessageSql); 225 | connection.query(userTouserNonReadMessageSql, function (err, results) { 226 | for (i = 0; i < results.length; i++) { 227 | var strObj = { 228 | 'userId': '', 229 | 'username': '', 230 | 'userProfilePhotoUrl': '', 231 | 'msg': '' 232 | }; 233 | strObj.userId = results[i].userId; 234 | strObj.username = results[i].defaultNickname; 235 | strObj.msg = results[i].message; 236 | console.log('strobj'); 237 | console.log(strObj); 238 | console.log('strObj end '); 239 | noticeRoom = roomUserToUser + results[i].userId; 240 | console.log("noticeRoom" + noticeRoom); 241 | socket.emit('mqtt', {'topic': String(roomUserToUser + results[i].userId), 242 | 'room': noticeRoom, 243 | 'payload': JSON.stringify(strObj) 244 | }); 245 | } 246 | }); 247 | //向用户推送未读的群信息,包括:活动,俱乐部,讨论组。 248 | groupNonReadMessageSql = 'select u.userId,u.defaultNickname, gcr.message,gcr.activityId,gcr.clubId,gcr.senderUserId, gcr.createTime ' + 249 | ' from GroupChatUserReadStatus gcs ,GroupChatRecord gcr,User u ' + 250 | ' where gcs.accepterUserId= ' + connection.escape(userInfo.userId) + 251 | ' and gcs.isRead=0 and gcr.groupChatRecordId = gcs.groupChatRecordId and gcr.senderUserId = u.userId'; 252 | connection.query(groupNonReadMessageSql, function (err, results) { 253 | for (i = 0; i < results.length; i++) { 254 | var strObj = { 255 | 'userId': '', 256 | 'username': '', 257 | 'userProfilePhotoUrl': '', 258 | 'msg': '' 259 | }; 260 | strObj.userId = results[i].userId; 261 | strObj.username = results[i].defaultNickname; 262 | strObj.msg = results[i].message; 263 | room = null; 264 | if (results[i].activityId != null) { 265 | room = roomActivity + results[i].activityId; 266 | } else { 267 | if (results[i].clubId != null) { 268 | room = roomClub + results[i].clubId; 269 | } 270 | } 271 | socket.emit('mqtt', {'topic': room, 272 | 'room': room, 273 | 'payload': JSON.stringify(strObj) 274 | }); 275 | } 276 | }); 277 | 278 | //推送完之后,将那些未读的信息全部设成已读。 279 | updateUserTouser = "update UserTouserChatRecord set isRead = 1 where isRead=0 and accepterUserId =" + connection.escape(userInfo.userId); 280 | updateGroup = "update GroupChatUserReadStatus set isRead = 1 where isRead=0 and accepterUserId =" + connection.escape(userInfo.userId); 281 | connection.query(updateUserTouser, function (err, results) { 282 | if (err) { 283 | connection.rollback(function () { 284 | throw err; 285 | }); 286 | } 287 | }); 288 | connection.query(updateGroup, function (err, results) { 289 | if (err) { 290 | connection.rollback(function () { 291 | throw err; 292 | }); 293 | } 294 | }); 295 | //处理去除重复,以免已经登录的用户,多次记录。 296 | //暂未处理。 297 | //暂时屏蔽了离线在线提示功能。 298 | // io.sockets.in(socket.topic).emit('users', { number:obj[socket.topic],room:room,payload:data.payload }); 299 | //想实现动态监听。 300 | 301 | // memcached.get(phpsession, function (err, data) { 302 | // console.log('session jin ru '); 303 | // console.log(typeof(data)); 304 | // console.log(data); 305 | // console.log('session tui chu'); 306 | // io.sockets.in(data.topic).emit('mqtt',{'topic': String(data.topic), 307 | // 'room':room, 308 | // 'payload':String(data)}); 309 | // 310 | // }); 311 | }); 312 | socket.on('publish', function (data) { 313 | console.log('--- publish to ' + data.topic + ' msg:' + data.payload); 314 | room = data.topic; //取得当前room. 315 | io.sockets.in(data.topic).emit('mqtt', {'topic': String(data.topic), 316 | 'room': room, 317 | 'payload': String(data.payload)}); 318 | // userInfo = eval('(' + data.payload + ')'); 319 | userInfo = JSON.parse(data.payload); 320 | msg = stripscript(userInfo.msg); 321 | timestamp = new Date().getTime(); 322 | groupChatInfo = room.split("-"); 323 | toGroupId = groupChatInfo[1]; 324 | portrait = userInfo.userProfilePhotoUrl; 325 | //查询出对应群组的所有人的手机clientId. 326 | groupType = room.split("-"); //字符分割 327 | console.log("groupType"); 328 | console.log(groupType); 329 | switch (groupType['0']) { 330 | case 'club': 331 | sql = "select userClientId,userId from UserClient where userId in( select userId from KuulabuUser where kuulabuId = " + connection.escape(groupType['1']) + ")"; 332 | insertGroupChatRecord = "insert into GroupChatRecord (message,createTime,clubId,senderUserId) values(" + 333 | "'" + msg + "'," + 334 | timestamp + "," + 335 | toGroupId + "," + 336 | userInfo.userId + 337 | ")"; 338 | groupUsersSql = " select userId from KuulabuUser where kuulabuId = " + connection.escape(groupType['1']); 339 | break; 340 | case 'activity': 341 | sql = "select userClientId,userId from UserClient where userId in( select inviteeUserId from ActivityUserInvitation where activityId = " + connection.escape(groupType['1']) + ")"; 342 | insertGroupChatRecord = "insert into GroupChatRecord (message,createTime,activityId,senderUserId) values(" + 343 | "'" + msg + "'," + 344 | timestamp + "," + 345 | toGroupId + "," + 346 | userInfo.userId + 347 | ")"; 348 | groupUsersSql = " select inviteeUserId as userId from ActivityUserInvitation where activityId = " + connection.escape(groupType['1']); 349 | break; 350 | case 'group': 351 | break; 352 | default: 353 | sql = ''; 354 | } 355 | console.log("sql:" + sql); 356 | mqttContent = '{"isSuccess":true,"message":"' + msg + '","type":"CHAT_ROOM","portrait":"' + portrait + '"}'; 357 | //将聊天记录插入数据库。 358 | connection.query(insertGroupChatRecord, function (err, results) { 359 | if (err) { 360 | connection.rollback(function () { 361 | throw err; 362 | }); 363 | } 364 | insertId = results.insertId; 365 | connection.query(groupUsersSql, function (err, results) { 366 | console.log(results); 367 | for (i = 0; i < results.length; i++) { 368 | // if(results[i]['userId'] ==userInfo.userId ){ 369 | // isRead = true; 370 | // timestamp=new Date().getTime(); 371 | // }else{ 372 | // isRead = false; 373 | // timestamp = 0; 374 | // } 375 | //在线的全部标识为已读。 376 | groupUser = roomUserToUser + results[i]['userId']; 377 | if (socketMap.hasOwnProperty(groupUser)) { 378 | isRead = true; 379 | timestamp = new Date().getTime(); 380 | } else { 381 | isRead = false; 382 | timestamp = 0; 383 | } 384 | insertGroupChatUserReadStatus = "insert into GroupChatUserReadStatus (isRead,readTime,groupChatRecordId,accepterUserId) values(" + 385 | isRead + "," + 386 | timestamp + "," + 387 | insertId + "," + 388 | results[i]['userId'] + 389 | ")"; 390 | console.log(insertGroupChatUserReadStatus); 391 | connection.query(insertGroupChatUserReadStatus, function (err, results) { 392 | if (err) { 393 | connection.rollback(function () { 394 | throw err; 395 | }); 396 | } 397 | }) 398 | } 399 | }) 400 | 401 | connection.query(sql, function (err, results) { 402 | for (i = 0; i < results.length; i++) { 403 | client.publish('chat/' + results[i]['userClientId'], mqttContent); 404 | } 405 | }); 406 | }) 407 | // client.publish('chat/630e80953e11ac25',mqttContent); 408 | }); 409 | socket.on('userTouser-publish', function (data) { 410 | console.log('--- publish to ' + data.topic + ' msg:' + data.payload); 411 | // userInfo = eval('(' + data.payload + ')'); 412 | userInfo = JSON.parse(data.payload); 413 | message = stripscript(userInfo.msg); //发送内容 414 | console.log('message'); 415 | console.log(stripscript(message)); 416 | console.log('message end'); 417 | roomA = data.topic; //取得当前room. 418 | console.log("roomA:" + roomA); 419 | roomB = roomUserToUser + userInfo.userId; 420 | timestamp = new Date().getTime(); 421 | toUserInfo = roomA.split("-"); 422 | toUserId = toUserInfo[1]; 423 | if (socketMap.hasOwnProperty(roomA)) { 424 | console.log('点对点有值'); 425 | socketuserA = socketMap[roomA]; 426 | //主动发送消息 427 | socketuserA.emit('mqtt', {'topic': String(data.topic), 428 | 'room': roomB, 429 | 'payload': String(data.payload)}); 430 | //记录在线信息。 431 | $insertSql = "insert into UserTouserChatRecord(message,createTime,readTime,isRead,senderUserId,accepterUserId) values(" + 432 | "'" + message + "'," + +timestamp + ',' + +timestamp + "," + 433 | true + "," + +userInfo.userId + "," + +toUserId + 434 | ")"; 435 | connection.query($insertSql, function (err, result) { 436 | if (err) { 437 | connection.rollback(function () { 438 | throw err; 439 | }); 440 | } 441 | }) 442 | 443 | } else { 444 | //记录用户的离线信息 445 | $insertSql = "insert into UserTouserChatRecord(message,createTime,readTime,isRead,senderUserId,accepterUserId) values(" + 446 | "'" + message + "'," + +timestamp + ',' + +timestamp + "," + 447 | false + "," + +userInfo.userId + "," + +toUserId + 448 | ")"; 449 | console.log('insertSql'); 450 | console.log($insertSql); 451 | console.log('insertSql end ----'); 452 | connection.query($insertSql, function (err, result) { 453 | if (err) { 454 | connection.rollback(function () { 455 | throw err; 456 | }); 457 | } 458 | }) 459 | } 460 | //被动发送消息 461 | socketuserB = socketMap[roomB]; 462 | socketuserB.emit('mqtt', {'topic': String(data.topic), 463 | 'room': roomA, 464 | 'payload': String(data.payload)}); 465 | 466 | //将自己设为已读信息 467 | $insertSql = "insert into UserTouserChatRecord(message,createTime,readTime,isRead,senderUserId,accepterUserId) values(" + 468 | "'" + message + "'," + +timestamp + ',' + +timestamp + "," + 469 | true + "," + +userInfo.userId + "," + +userInfo.userId + 470 | ")"; 471 | connection.query($insertSql, function (err, result) { 472 | if (err) { 473 | connection.rollback(function () { 474 | throw err; 475 | }); 476 | } 477 | }) 478 | 479 | userInfo = eval('(' + data.payload + ')'); 480 | msg = userInfo.msg; 481 | portrait = userInfo.userProfilePhotoUrl; 482 | mqttConten_jsonObj = {'isSuccess': true, 'message': '"' + msg + '"', 'type': 'CHAT_ROOM', 'portrait': '"' + portrait + '"'}; 483 | mqttConten_jsonObj.portrait = portrait; 484 | mqttConten_jsonObj.message = msg; 485 | mqttContent = JSON.stringify(mqttConten_jsonObj); 486 | client.publish('chat/630e80953e11ac25', mqttContent); 487 | }); 488 | 489 | socket.on('disconnect', function () { 490 | obj[socket.topic]--; 491 | userId = socketArr[socket.id]; 492 | console.log("userId:" + userId); 493 | //查询当前socket用户的clients信息 494 | memcached.get(userId, function (err, result) { 495 | console.log("socket.id:" + socket.id); 496 | console.log(result); 497 | console.log("data"); 498 | var new_data = new Array(); 499 | result = new String(result); //强制转换为字符串类型,因为memcached获取的结果是object 500 | data = result.split(","); 501 | if (data) { 502 | if (data.in_array(socket.id)) { 503 | for (i = 0; i < data.length; i++) { 504 | console.log("i:" + i); 505 | console.log(data[i]); 506 | //删除已经退出的client 507 | if (data[i] == socket.id) { 508 | console.log("cun zai xiang deng de !"); 509 | } else { 510 | console.log('jin lai le '); 511 | new_data.push(data[i]); 512 | } 513 | } 514 | //如果新的数组对象长度为0,则删除memcached中此用户的clients信息。表示用户已经彻底下线。 515 | if (new_data.length == 0) { 516 | memcached.del(userId, function (err) { 517 | // stuff 518 | }); 519 | delete socketMap[roomUserToUser + userId]; 520 | } else { 521 | userClients = new_data.join(","); 522 | memcached.set(userId, new_data, 10000, function (err, result) { 523 | if (err) console.error(err); 524 | console.dir(result); //返回值为boolen值 525 | }); 526 | } 527 | } 528 | console.log('new_data exist start '); 529 | for (i = 0; i < new_data.length; i++) { 530 | console.log("new_data i=" + new_data[i]); 531 | } 532 | console.log('new_data exist end! '); 533 | } else { 534 | //if data is null or empty object or array 535 | } 536 | }); 537 | //测试删除的clients情况,测试用,应用上没什么作用。 538 | memcached.get(userId, function (err, data) { 539 | console.log('shan chu hou de '); 540 | // for(i=0;i -1) { 48 | this.splice(index, 1); 49 | } 50 | }; 51 | 52 | Array.prototype.in_array = function(e) 53 | { 54 | for(i=0;i/?~!@#¥……&*()——|{}【】‘;:”“'。,、?]") 98 | var rs = ""; 99 | for (var i = 0; i < s.length; i++) { 100 | rs = rs + s.substr(i, 1).replace(pattern, ''); 101 | } 102 | return rs; 103 | } 104 | 105 | 106 | //下步两项任务: 107 | // 1: 将用户所有的clientID记录进入memcached,并实现用户离线的自身的socket的清理断开。 108 | // 2: 查询当前socket用户的所有好友userId,并查询出都那些人在线。 109 | // 3: 查询当前socket用户加入的所有俱乐部的clubId,并统计在线人数。 110 | // 4: 查询当前socket用户加入的活动的activityId,并统计在线人数。 111 | 112 | //memcached.get('1g8n9qneetpiapup2utdf9qm12_userId', function (err, data) { 113 | // console.log('session jin ru 111'); 114 | // console.dir( data ); 115 | // console.log('session tui chu 222'); 116 | //}); 117 | io.sockets.on('connection', function (socket) { 118 | var topic = ''; 119 | socket.on('subscribe', function (data) { 120 | var count = 1; 121 | socket.topic = data.topic; 122 | socket.payload = data.payload; 123 | room = data.topic; 124 | userInfo = JSON.parse(data.payload); 125 | phpsession = userInfo.phpsession+'_userId'; 126 | //生成socketId与userId的键值对: (key=>value) 如: socketId => userId 127 | socketArr[socket.id]=userInfo.userId; 128 | console.log('socketArr'); 129 | console.log(socketArr); 130 | console.log('socketArr'); 131 | //用户只要登录就订阅所有的消息。 132 | //1:首先订阅个人信息 133 | socketMap[roomUserToUser+userInfo.userId] = socket; 134 | //订阅俱乐部/活动/讨论组的信息。 135 | sql = "select activityId from ActivityUserInvitation where inviteeUserId= "+ connection.escape(userInfo.userId); 136 | connection.query(sql, function(err, results) { 137 | for(i=0;i data.length) { 29 | error('Error', 'Invalid'); 30 | } 31 | buf.push(chr); 32 | chr = data.slice(offset + (i - 1), offset + i); 33 | i += 1; 34 | } 35 | return [buf.length, buf.join('')]; 36 | }, 37 | read_chrs = function (data, offset, length) { 38 | var i, chr, buf; 39 | 40 | buf = []; 41 | for (i = 0; i < length; i++) { 42 | chr = data.slice(offset + (i - 1), offset + i); 43 | buf.push(chr); 44 | length -= utf8Overhead(chr); 45 | } 46 | return [buf.length, buf.join('')]; 47 | }, 48 | _unserialize = function (data, offset) { 49 | var dtype, dataoffset, keyandchrs, keys, 50 | readdata, readData, ccount, stringlength, 51 | i, key, kprops, kchrs, vprops, vchrs, value, 52 | chrs = 0, 53 | typeconvert = function (x) { 54 | return x; 55 | }; 56 | 57 | if (!offset) { 58 | offset = 0; 59 | } 60 | dtype = (data.slice(offset, offset + 1)).toLowerCase(); 61 | 62 | dataoffset = offset + 2; 63 | 64 | switch (dtype) { 65 | case 'i': 66 | typeconvert = function (x) { 67 | return parseInt(x, 10); 68 | }; 69 | readData = read_until(data, dataoffset, ';'); 70 | chrs = readData[0]; 71 | readdata = readData[1]; 72 | dataoffset += chrs + 1; 73 | break; 74 | case 'b': 75 | typeconvert = function (x) { 76 | return parseInt(x, 10) !== 0; 77 | }; 78 | readData = read_until(data, dataoffset, ';'); 79 | chrs = readData[0]; 80 | readdata = readData[1]; 81 | dataoffset += chrs + 1; 82 | break; 83 | case 'd': 84 | typeconvert = function (x) { 85 | return parseFloat(x); 86 | }; 87 | readData = read_until(data, dataoffset, ';'); 88 | chrs = readData[0]; 89 | readdata = readData[1]; 90 | dataoffset += chrs + 1; 91 | break; 92 | case 'n': 93 | readdata = null; 94 | break; 95 | case 's': 96 | ccount = read_until(data, dataoffset, ':'); 97 | chrs = ccount[0]; 98 | stringlength = ccount[1]; 99 | dataoffset += chrs + 2; 100 | 101 | readData = read_chrs(data, dataoffset + 1, parseInt(stringlength, 10)); 102 | chrs = readData[0]; 103 | readdata = readData[1]; 104 | dataoffset += chrs + 2; 105 | if (chrs != parseInt(stringlength, 10) && chrs != readdata.length) { 106 | error('SyntaxError', 'String length mismatch'); 107 | } 108 | break; 109 | case 'a': 110 | readdata = {}; 111 | 112 | keyandchrs = read_until(data, dataoffset, ':'); 113 | chrs = keyandchrs[0]; 114 | keys = keyandchrs[1]; 115 | dataoffset += chrs + 2; 116 | 117 | for (i = 0; i < parseInt(keys, 10); i++) { 118 | kprops = _unserialize(data, dataoffset); 119 | kchrs = kprops[1]; 120 | key = kprops[2]; 121 | dataoffset += kchrs; 122 | 123 | vprops = _unserialize(data, dataoffset); 124 | vchrs = vprops[1]; 125 | value = vprops[2]; 126 | dataoffset += vchrs; 127 | 128 | readdata[key] = value; 129 | } 130 | 131 | dataoffset += 1; 132 | break; 133 | default: 134 | error('SyntaxError', 'Unknown / Unhandled data type(s): ' + dtype); 135 | break; 136 | } 137 | return [dtype, dataoffset - offset, typeconvert(readdata)]; 138 | } 139 | ; 140 | 141 | dataoffset = 0; 142 | var res = {}; 143 | while (dataoffset < data.length) 144 | { 145 | keyandchrs = read_until(data, dataoffset, '|'); 146 | chrs = keyandchrs[0]; 147 | key = keyandchrs[1]; 148 | dataoffset += chrs + 1; 149 | subdata = _unserialize((data + ''), dataoffset); 150 | dataoffset += subdata[1]; 151 | res[key] = subdata[2]; 152 | 153 | } 154 | return res 155 | } 156 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "hongshuai.yuan", 3 | "name": "mqtt-socketIo-php", 4 | "description": " 实现了php和nodejs通过mqtt和socket.io实现的消息通讯", 5 | "version": "0.0.1", 6 | "repository": { 7 | "url": "" 8 | }, 9 | "engines": { 10 | "node": "v0.10.22" 11 | }, 12 | "main" : "./lib/mqttSocketIoPhp.js", 13 | "bin" : "./bin/mqttSocketIoPhp.js", 14 | "scripts": { 15 | "test": "node ./test/mqttSocketIoPhp.js" 16 | }, 17 | "dependencies": {}, 18 | "devDependencies": {}, 19 | "optionalDependencies": {} 20 | } 21 | -------------------------------------------------------------------------------- /test/mqttSocketIoPhp.js: -------------------------------------------------------------------------------- 1 | var sys = require('sys'); 2 | var net = require('net'); 3 | var mqtt = require('mqtt'); 4 | var client = mqtt.createClient(); 5 | var io = require('socket.io').listen(5000); 6 | var roomOnlineNum = new Array(); 7 | var obj={}; 8 | io.sockets.on('connection', function (socket) { 9 | var topic = ''; 10 | socket.on('subscribe', function (data) { 11 | console.log(data); 12 | var count = 1; 13 | socket.topic = data.topic; 14 | socket.payload = data.payload; 15 | room = data.topic; 16 | console.log("username"+data.payload); 17 | if(!obj[room]){ 18 | obj[room] = count++; 19 | }else{ 20 | obj[room]++; 21 | } 22 | socket.join(data.topic); 23 | client.subscribe(data.topic); //向特定的用户发送信息。 24 | io.sockets.in(socket.topic).emit('users', { number:obj[socket.topic],payload:data.payload }); 25 | }); 26 | socket.on('publish',function(data){ 27 | console.log('--- publish to '+data.topic+' msg:'+data.payload); 28 | io.sockets.in(data.topic).emit('mqtt',{'topic': String(data.topic), 29 | 'payload':String(data.payload)}); 30 | // client.publish(data.topic,data.payload); 31 | }); 32 | socket.on('disconnect', function () { 33 | obj[socket.topic]--; 34 | console.log('User disconnected. ' + obj[socket.topic] + ' user(s) present.'); 35 | io.sockets.in(socket.topic).emit('usersDisconnect', { number: obj[socket.topic],payload:socket.payload }); 36 | }); 37 | }); 38 | 39 | client.on('message', function(topic, payload){ 40 | console.log('teststest'); 41 | console.log("topic"+topic) 42 | console.log(payload ); 43 | sys.puts(topic+'='+payload); 44 | io.sockets.in(topic).emit('mqtt',{'topic': String(topic), 45 | 'payload':String(payload)}); 46 | }); 47 | 48 | --------------------------------------------------------------------------------