您的位置:首页 > 其它

使用socket.io+express实现网页聊天的实践

2014-02-26 19:04 585 查看
近期,有客户提出希望尝试用HTML5相关技术实现在线交互和文件传输,于是乎找到了socket.io,通过搜索引擎和官方帮助实现了简单的聊天和指定用户的消息广播,在此总结跟大家分享。

A.环境安装与配置

首先,安装nodejs,直接官网下载对应平台对应版本即可。地址为http://nodejs.org/安装,我安装的是Mac版的dmg。

接下来就可以使用终端来安装socket.io和express模块,命令如下:

sudo sh
npm install -g socket.io
npm install -g express
B.socket.io简介

node.js提供了高效的服务端运行环境,为了解决浏览器的兼容性问题,同时提供客户端与服务端一致的编程体验,于是socket.io诞生了。

socket.io
是一个为实时应用提供跨平台实时通信的库,包括服务器端和客户端。socket.io 旨在使实时应用在每个浏览器和移动设备上成为可能,模糊不同的传输机制之间的差异。只要在服务器端启动服务端js脚本(node app.js),就在某个端口开启了一个实时监听的通道,只要客户端连接就可以进行相互通讯。下面是官网socket.io使用的最简单示例:

SERVER

var io = require('socket.io').listen(80);

io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
CLIENT

<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost');
socket.on('news', function (data) {
console.log(data);
socket.emit('my other event', { my: 'data' });
});
</script>
C.使用socket.io和express构建网页聊天室

环境搭建好之后,构思应用场景,客户端页面加载完成后,自动创建一个用户名(可以是登陆名),然后跟服务器端通讯,发送用户名,服务器端广播欢迎用户的消息,同时纪录用户名称和ip等信息。正常聊天时可以通过广播机制发送消息,每一个人员都可收听的到,而特殊情况可以@用户名只将消息发送给指定的用户群(room机制)。同时,在用新用户登陆或者离开是,系统需要更新每个用户的用户列表并广播用户退出的信息。

服务端主要代码

//记录在线用户
var userList={};

//记录IP
var ipList={};

//WebSocket连接监听
io.on('connection', function (socket) {
socket.emit('open');
// 打印连接信息
var address = socket.handshake.address;
console.log("New connection from " + address.address + ":" + address.port);

// 构造客户端对象
var client = {
socket:socket,
name:false
}

// 对message事件的监听
socket.on('message', function(msg){
var obj = {time:getTime()};

// 判断是不是第一次连接,消息为用户名称
if(!client.name){
client.name = msg;
obj['text']=msg;
obj['author']='System';
obj['type']='welcome';
console.log(client.name + ' login');

var usertxt=client.name;
//纪录用户和ip信息,用于房间用户筛选,局部通讯
if (!userList[usertxt]) {
userList[usertxt] = 1;
} else {
userList[usertxt] ++;
}
ipList[socket.handshake.address.address]=usertxt;

//返回欢迎语
socket.emit('system',obj);
//广播新用户已登陆
socket.broadcast.emit('system',obj);

var objusr = {time:getTime()};
objusr['text']=userList;
objusr['author']='System';
objusr['type']='userConnected';
//更新用户列表
io.sockets.emit('system',objusr);
}else{

//如果不是第一次的连接,正常的聊天消息
obj['text']=msg;
obj['author']=client.name;
obj['type']='message';
console.log(client.name + ' say: ' + msg);

var arr=msg.split("@");
//将消息用@符号进行分割,筛选出关联的在线用户
if(arr.length<3 || arr[0]!="")
{
// 返回消息(可以省略)
socket.emit('message',obj);
// 广播向其他用户发消息
socket.broadcast.emit('message',obj);
}
else
{
var flag=0;
//根据用户名称找到用户对应ip地址,再通过ip地址找到对应的socket连接,将@关联的用户socket加入到一个room中
io.sockets.clients().forEach(function (socket) {
for(ip in ipList)
{
for(i=0;i<arr.length;i++)
{
if(ipList[ip]==arr[i] && ip==socket.handshake.address.address)
{
//加入到指定房间
socket.join('someUsers');
flag++;
}
}
}
});
if(flag==0)
{
socket.join('me');
obj['text']="请核实您关联的用户名!";
obj['author']='系统';
io.sockets.in('me').emit('message', obj);
}
else
{
obj['text']=arr[arr.length-1];
//将消息发送给加入该房间的用户
io.sockets.in('someUsers').emit('message', obj);
}
}

}
});

//监听出退事件
socket.on('disconnect', function () {
var obj = {
time:getTime(),
color:client.color,
author:'System',
text:client.name,
type:'disconnect'
};
var userName=client.name;

if (userList[userName]) {
userList[userName] --;
if (userList[userName] == 0) {
delete userList[userName];
}
}

for(ip in ipList)
{
if (ipList[ip]==client.name)
{

delete ipList[ip];
}

console.log(ip);
}

// 广播用户已退出
socket.broadcast.emit('system',obj);
console.log(client.name + 'Disconnect');

var objusr = {time:getTime()};

objusr['text']=userList;
objusr['author']='System';
objusr['type']='userConnected';

socket.broadcast.emit('system',objusr);
});
其次,express的简单配置

//express基本配置
app.configure(function(){
app.set('port', process.env.PORT || 3000);
app.set('web', __dirname + '/web');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
});

app.configure('development', function(){
app.use(express.errorHandler());
});

// 指定webscoket的客户端的html文件
app.get('/', function(req, res){
res.sendfile('web/index.html');
});

server.listen(app.get('port'), function(){
console.log("Express server listening on port " + app.get('port'));
});


因为nojo可以直接运行js,所以开发应用可phonegap打包到不同平台,同时也可以支持在线的访问。

客户端

与服务器端对应的响应代码

var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
       var maxPos = $chars.length;
  		 var usr = '';
 	    for (i = 0; i < 6; i++) {
    		usr += $chars.charAt(Math.floor(Math.random() * maxPos));
 	    }

var userName=usr;

//建立websocket连接
socket = io.connect('http://192.168.0.23:3000');
socket.send(userName);
//收到server的连接确认
socket.on('open',function(json){
status.text(json);
});

//监听system事件,判断welcome或者disconnect,打印系统消息信息
socket.on('system',function(json){
var p = '';
if (json.type === 'welcome'){
if(userName==json.text) status.text(userName + ':');
p = '系统@'+ json.time+ ':欢迎' + json.text +'!\n';

var txt=content.val();
content.text(txt+p);
}else if(json.type=='userConnected')
{
p=json.text;
var usrlist='';
for(usr in p)
usrlist=usrlist+usr+'\n';
userlist.html(usrlist);
}
else if(json.type == 'disconnect'){
p = '系统@'+ json.time+ ':再见' + json.text +'!\n';

var txt=content.val();

if(json.text=='false')
return;
else
content.text(txt+p);
}

});

//监听message事件,打印消息信息
socket.on('message',function(json){
var p = json.author+'@'+ json.time+ ' : '+json.text + '\n';

var txt=content.val();
content.html(txt+p);
});

//通过“回车”提交聊天信息
input.keydown(function(e) {
if (e.keyCode === 13) {
var msg = $(this).val();
if (!msg) return;
socket.send(msg);
$(this).val('');
if (userName === false) {
userName = msg;
}
}
});


参考资料

cnodechat聊天室设计及实现介绍


socket.io 简介及使用

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: