node php聊天室,利用socket.io实现多人聊天室(基于Nodejs)

利用socket.io实现多人聊天室(基于Nodejs)

socket.io简介

在Html5中存在着这样的一个新特性,引入了websocket,关于websocket的内部实现原理可以看这篇文章,这篇文章讲述了websocket无到有,根据协议,分析数据帧的头,进行构建websocket。虽然代码短,但可以很好地体现websocket的原理。

这个特性提供了浏览器端和服务器端的基于TCP连接的双向通道。但是并不是所有的浏览器都支持websocket特性,故为了磨平浏览器间的差异,为开发者提供统一的接口,引入了socket.io模块。在不支持websoket的浏览器中,socket.io可以降级为其他的通信方式,比如有AJAX long polling ,JSONP Polling等。

模块安装

新建一个package.json文件,在文件中写入如下内容:

{

"name": "socketiochatroom",

"version": "0.0.1",

"dependencies": {

"socket.io": "*",

"express":"*"

}

}

npm install

执行完这句,node将会从npm处下载socket.io和express模块。

服务器端的实现

在文件夹中添加index.js文件,并在文件中写入如下内容:

/**

* Created by bamboo on 2016/3/31.

*/

var app = require('express')();

var http = require('http').Server(app);

var io = require('socket.io')(http);

app.get('/', function (req, res) {

"use strict";

res.end("

socket server")

});

/*在线人员*/

var onLineUsers = {};

/* 在线人数*/

var onLineCounts = 0;

/*io监听到存在链接,此时回调一个socket进行socket监听*/

io.on('connection', function (socket) {

console.log('a user connected');

/*监听新用户加入*/

socket.on('login', function (user) {

"use strict";

//暂存socket.name 为user.userId;在用户退出时候将会用到

socket.name = user.userId;

/*不存在则加入 */

if (!onLineUsers.hasOwnProperty(user.userId)) {

//不存在则加入

onLineUsers[user.userId] = user.userName;

onLineCounts++;

}

/*一个用户新加入,向所有客户端监听login的socket的实例发送响应,响应内容为一个对象*/

io.emit('login', {onLineUsers: onLineUsers, onLineCounts: onLineCounts, user: user});

console.log(user.userName, "加入了聊天室");//在服务器控制台中打印么么么用户加入到了聊天室

});

/*监听用户退出聊天室*/

socket.on('disconnect', function () {

"use strict";

if (onLineUsers.hasOwnProperty(socket.name)) {

var user = {userId: socket.name, userName: onLineUsers[socket.name]};

delete onLineUsers[socket.name];

onLineCounts--;

/*向所有客户端广播该用户退出群聊*/

io.emit('logout', {onLineUsers: onLineUsers, onLineCounts: onLineCounts, user: user});

console.log(user.userName, "退出群聊");

}

})

/*监听到用户发送了消息,就使用io广播信息,信息被所有客户端接收并显示。注意,如果客户端自己发送的也会接收到这个消息,故在客户端应当存在这的判断,是否收到的消息是自己发送的,故在emit时,应该将用户的id和信息封装成一个对象进行广播*/

socket.on('message', function (obj) {

"use strict";

/*监听到有用户发消息,将该消息广播给所有客户端*/

io.emit('message', obj);

console.log(obj.userName, "说了:", obj.content);

});

});

/*监听3000*/

http.listen(3000, function () {

"use strict";

console.log('listening 3000');

});

运行服务器端程序

node index.js

输出

listening 3000

此时在浏览器中打开localhost:3000会得到这样的结果:

原因是在代码中只对路由进行了如下设置

app.get('/', function (req, res) {

"use strict";

res.end("

socket server")

});

服务器端主要是提供socketio服务,并没有设置路由。

客户端的实现

在客户端建立如下的目录和文件,其中json3.min.js可以从网上下载到。

client

- - - client.js

- - - index.html

- - - json3.min.js

- - - style.css

在index.html中

1301群聊

输入你在群聊中的昵称

1301群聊

提交

在client.js中

/**

* Created by bamboo on 2016/3/31.

*/

/*即时运行函数*/

(function () {

"use strict";

var d = document,

w = window,

dd = d.documentElement,

db = d.body,

dc = d.compatMode === "CSS1Compat",

dx = dc ? dd : db,

ec = encodeURIComponent,

p = parseInt;

w.CHAT = {

msgObj: d.getElementById("message"),

screenHeight: w.innerHeight ? w.innerHeight : dx.innerHeight,

userName: null,

userId: null,

socket: null,

/*滚动条始终在最底部*/

scrollToBottom: function () {

w.scrollTo(0, this.msgObj.clientHeight);

},

/*此处仅为简单的刷新页面,当然可以做复杂点*/

logout: function () {

// this.socket.disconnect();

w.top.location.reload();

},

submit: function () {

var content = d.getElementById('content').value;

if (content != '') {

var obj = {

userId: this.userId,

userName: this.userName,

content: content

};

//如在服务器端代码所说,此对象就行想要发送的信息和发送人组合成为对象一起发送。

this.socket.emit('message', obj);

d.getElementById('content').value = '';

}

return false;

},

/**客户端根据时间和随机数生成ID,聊天用户名称可以重复*/

genUid: function () {

return new Date().getTime() + "" + Math.floor(Math.random() * 889 + 100);

},

/*更新系统信息

主要是在客户端显示当前在线人数,在线人列表等,当有新用户加入或者旧用户退出群聊的时候做出页面提示。*/

updateSysMsg: function (o, action) {

var onLineUsers = o.onLineUsers;

var onLineCounts = o.onLineCounts;

var user = o.user;

//更新在线人数

var userHtml = '';

var separator = '';

for (var key in onLineUsers) {

if (onLineUsers.hasOwnProperty(key)) {

userHtml += separator + onLineUsers[key];

separator = '、';

}

}

//插入在线人数和在线列表

d.getElementById('onLineCounts').innerHTML = '当前共有' + onLineCounts + "在线列表: " + userHtml;

//添加系统消息

var html = '';

html += '

';

html += user.userName;

html += (action === "login") ? "加入了群聊" : "退出了群聊";

html += '';

var section = d.createElement('section');

section.className = 'system J-mjrlinkWrap J-cutMsg';

section.innerHTML = html;

this.msgObj.appendChild(section);

this.scrollToBottom();

},

/*用户提交用户名后,将loginbox设置为不显示,将chatbox设置为显示*/

userNameSubmit: function () {

var userName = d.getElementById('userName').value;

if (userName != '') {

d.getElementById('userName').value = '';

d.getElementById('loginbox').style.display = 'none';

d.getElementById('chatbox').style.display = 'block';

this.init(userName);//调用init方法

}

return false;

},

//用户初始化

init: function (userName) {

//随机数生成uid

this.userId = this.genUid();

this.userName = userName;

d.getElementById('showUserName').innerHTML = this.userName;//[newpidian]|[退出]

this.scrollToBottom();

//连接socketIO服务器,newpidian的IP地址

this.socket = io.connect('192.168.3.155:3000');

//向服务器发送某用户已经登录了

this.socket.emit('login', {userId: this.userId, userName: this.userName});

//监听来自服务器的login,即在客户端socket.emit('login ')发送后,客户端就会收到来自服务器的

// io.emit('login', {onLineUsers: onLineUsers, onLineCounts: onLineCounts, user: user});

/*监听到有用户login了,更新信息*/

this.socket.on('login', function (o) {

//更新系统信息

CHAT.updateSysMsg(o, 'login');

});

/*监听到有用户logout了,更新信息*/

this.socket.on('logout', function (o) {

CHAT.updateSysMsg(o, 'logout');

});

//var obj = {

// userId: this.userId,

// userName: this.userName,

// content: content

//};

/*监听到有用户发送消息了*/

this.socket.on("message", function (obj) {

//判断消息是不是自己发送的

var isMe = (obj.userId === CHAT.userId);

var contentDiv = '

' + obj.content + '';

var userNameDiv = '' + obj.userName + '';

var section = d.createElement('section');

if (isMe) {

section.className = 'user';

section.innerHTML = contentDiv + userNameDiv;

} else {

section.className = 'service';

section.innerHTML = userNameDiv + contentDiv;

}

CHAT.msgObj.appendChild(section);

CHAT.scrollToBottom();

});

}

}

/*控制键键码值(keyCode)

按键 键码 按键 键码 按键 键码 按键 键码

BackSpace 8 Esc 27 Right Arrow 39 -_ 189

Tab 9 Spacebar 32 Dw Arrow 40 .> 190

Clear 12 Page Up 33 Insert 45 /? 191

Enter 13 Page Down 34 Delete 46 `~ 192

Shift 16 End 35 Num Lock 144 [{ 219

Control 17 Home 36 ;: 186 \| 220

Alt 18 Left Arrow 37 =+ 187 ]} 221

Cape Lock 20 Up Arrow 38 ,< 188 '" 222

* */

//通过“回车键”提交用户名

d.getElementById('userName').onkeydown = function (e) {

console.log(e);

e = e || event;

if (e.keyCode === 13) {

CHAT.userNameSubmit();

}

};

//通过“回车键”提交聊天内容

d.getElementById('content').onkeydown = function (e) {

e = e || event;

if (e.keyCode === 13) {

CHAT.submit();

}

};

})();

本文原创发布php中文网,转载请注明出处,感谢您的尊重!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值