http://www.cnblogs.com/sword-successful/p/4987124.html
前言
周末断断续续的写了第一个socket.io Demo。初次接触socket.io是从其官网看到的,看着get started做了一遍,根据官网的Demo能提供简单的服务端和客户端通讯。 这个Demo的过程中用到最多的就是订阅事件、触发事件、广播事件。
根据官网完成Demo后,看到下面提到了几个问题,又继续实现了四个功能,其它几个还要继续实现。
①、当有新用户登录或离开时广播消息。
②、添加昵称。我在demo中的做法是把用户输入的第一条消息作为昵称。
③、发送消息时自己发送的消息不再给自己发送,其实也就是只调用广播(socket.broadcast.emit)消息的方法即可。
④、显示当前在线用户和在线人数。
开发环境
node:0.12.7
express:4.13.7
socket.io:1.3.7
官网Demo中遇到的问题
①、客户端html页面<script src="/socket.io/socket.io.js"></script>
这样引用js代码没搞明白,百度搜索了一下,有人解释说是因为express提供的框架转化了路径,所以你这样做是可以引用到该js的,刚接触应该会感到意外,但是我实验如果你只是引用了express而不是用express创建项目的话可能还是不管用。
②、在体验Demo并且看其他人写的例子中发现,很多情况下客户端和服务端触发的事件名称都相同,不理解这种情况他们是同一个事件吗? 会不会产生冲突呢?
效果图
1、系统初始化,当你打开页面时会提示你连接至服务器,你输入第一条消息就是昵称。
2、输入昵称,以同样的方式再打开几个Tab页,输入昵称。
3、两个客户端聊天
服务端实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
var
express=require(
'express'
);
var
app=express();
var
http=require(
'http'
).Server(app);
var
io=require(
'socket.io'
)(http);
app.get(
'/'
,
function
(req,res){
res.sendFile(__dirname+
'/index.html'
);
});
var
onlineUserCount=0;
//客户端连接数量
var
onlineUsers={};
//统计客户端登录用户
io.on(
'connection'
,
function
(socket){
socket.emit(
'open'
);
//通知客户端已连接
//构造客户端对象
var
client={
socket:socket,
name:
false
}
//监听客户端的chat message事件, 该事件由客户端触发
//当服务端收到消息后,再把该消息播放出去,继续触发chat message事件, 然后在客户端监听chat message事件。
socket.on(
'chat message'
,
function
(msg){
console.log(
'chat message:'
+msg);
var
obj={time:getTime()};
//构建客户端返回的对象
//判断是不是第一次连接,以第一条消息作为昵称
if
(!client.name){
onlineUserCount++;
client.name=msg;
obj[
'text'
]=client.name;
obj[
'author'
]=
'Sys'
;
obj[
'type'
]=
'welcome'
;
obj[
'onlineUserCount'
]=onlineUserCount;
socket.name=client.name;
//用户登录后设置socket.name, 当退出时用该标识删除该在线用户
if
(!onlineUsers.hasOwnProperty(client.name)){
onlineUsers[client.name]=client.name;
}
obj[
'onlineUsers'
]=onlineUsers;
//当前在线用户集合
console.log(client.name+
' login,当前在线人数:'
+onlineUserCount);
//返回欢迎语
socket.emit(
'system'
,obj);
//发送给自己的消息
//广播新用户已登录
socket.broadcast.emit(
'system'
,obj);
//向其他用户发送消息
}
else
{
//如果不是第一次聊天,则返回正常的聊天消息
obj[
'text'
]=msg;
obj[
'author'
]=client.name;
obj[
'type'
]=
'message'
;
console.log(client.name+
' say:'
+msg);
socket.emit(
'chat message'
,obj);
//发送给自己的消息 , 如果不想打印自己发送的消息,则注释掉该句。
socket.broadcast.emit(
'chat message'
,obj);
//向其他用户发送消息
}
//io.emit('chat message',msg);
});
socket.on(
'disconnect'
,
function
(){
onlineUserCount--;
if
(onlineUsers.hasOwnProperty(socket.name)){
delete
onlineUsers[client.name];
}
var
obj={
time:getTime(),
author:
'Sys'
,
text:client.name,
type:
'disconnect'
,
onlineUserCount:onlineUserCount,
onlineUsers:onlineUsers
};
//广播用户退出
socket.broadcast.emit(
'system'
,obj);
//用户登录和退出都使用system事件播报
console.log(client.name+
' disconnect,当前在线人数:'
+onlineUserCount);
});
});
http.listen(3000,
function
(){
console.log(
'server begin...'
);
});
var
getTime=
function
(){
var
date =
new
Date();
return
date.getHours()+
":"
+date.getMinutes()+
":"
+date.getSeconds();
}
var
getColor=
function
(){
var
colors = [
'aliceblue'
,
'antiquewhite'
,
'aqua'
,
'aquamarine'
,
'pink'
,
'red'
,
'green'
,
'orange'
,
'blue'
,
'blueviolet'
,
'brown'
,
'burlywood'
,
'cadetblue'
];
return
colors[Math.round(Math.random() * 10000 % colors.length)];
}
|
客户端实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
<!doctype html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
div { background:
#000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
div input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
div button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
p{padding:5px 10px;}
</style>
</head>
<body>
<p id=
"onlineUser"
>在线人数:0</p>
<ul id=
"messages"
></ul>
<div action=
""
>
<input id=
"m"
autocomplete=
"off"
/><button>Send</button>
</div>
<script type=
"text/javascript"
>
var
myName=
false
;
socket.on(
'open'
,
function
(){
$(
'#messages'
).append($(
'<li>'
).text(
'已连接至服务器,请输入昵称'
));
});
//监听system事件,判断welcome或者disconnect,打印系统消息
socket.on(
'system'
,
function
(json){
var
sep=
''
;
var
onlinehtml=
''
;
var
onlineUsers=json.onlineUsers;
for
(key
in
onlineUsers){
if
(onlineUsers.hasOwnProperty(key)){
onlinehtml+=sep+onlineUsers[key];
sep=
'、'
;
}
}
if
(json.type===
'welcome'
){
$(
'#messages'
).append($(
'<li>'
).text(
'Sys('
+json.time+
')welcome '
+json.text));
$(
'#onlineUser'
).text(
'在线人数:'
+json.onlineUserCount+
'。在线列表:'
+onlinehtml);
}
else
if
(json.type===
'disconnect'
){
$(
'#messages'
).append($(
'<li>'
).text(
'Sys('
+json.time+
')bye '
+json.text+
''
));
$(
'#onlineUser'
).text(
'在线人数:'
+json.onlineUserCount+
'。在线列表:'
+onlinehtml);
}
});
//监听服务端的chat message事件,接受每一条消息
socket.on(
'chat message'
,
function
(json){
$(
'#messages'
).append($(
'<li>'
).text(json.author+
'('
+json.time+
')'
+
':'
+json.text));
});
$(
'#m'
).keydown(
function
(e){
if
(e.keyCode===13){
socket.emit(
'chat message'
,$(
'#m'
).val());
//socket.send($('#m').val());
$(
'#m'
).val(
''
);
if
(myName===
false
){
myName=$(
'#m'
).val();
}
}
})
</script>
</body>
</html>
|
总结
做这个Demo的过程中,感觉目前用到最多的就是订阅事件和发布事件,然后客户端和服务端接受相应的参数,另外一个就是服务端和客户端通信可以完全用JSON格式传参,的确很方便。 目前掌握的方法就是socket.emit()和socket.broadcast.emit(),还没有搞明白emit()和send()的区分。
提供代码下载地址:http://pan.baidu.com/s/1mgm12Rm