这不是一个项目而是一个适合刚開始学习的人学习的样例。主要实现了下面基本功能:
1:群聊。每个人都能够收到其它人的消息,以及能够发消息给其它人,每个人用ip地址标识。
2:显示当前在线用户。
3:每个用户登入登出。其它人都能够看到。
4:每个用户能够看到其它人是否正在输入消息。
实现方式没有选择低效的轮询方式,而是採用基于websocket协议的socket.io模块,websocket协议同意在client与服务端之间建立一个全双工的通信通道。因此服务端能够主动推消息给client。相比传统的轮询,实时性更好。
前端代码例如以下:
<!doctype html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #fc5bff; padding: 2px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
form button { width: 9%; background: rgb(217, 222, 221); 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; }
</style>
</head>
<body>
<ul id="messages"></ul>
<ul><li id='typingshow'></li></ul>
<div id='joinshow'></div>
<div id='leftshow'></div>
<div id='onlineshow'></div>
<form action="">
<input id="m" autocomplete="off" /><button id='btn'>Send</button>
</form>
<script src="jquery-1.10.2.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
var typingIps={};
var typing=false;
var lastTypingTime;
function updateTyping() {
if (!typing) {
typing = true;
socket.emit('typing');
}
lastTypingTime = (new Date()).getTime();
setTimeout(function () {
var typingTimer = (new Date()).getTime();
var timeDiff = typingTimer - lastTypingTime;
if (timeDiff >= 400 && typing) {
socket.emit('stop typing');
typing = false;
}
}, 400);
}
$('form').submit(function(){
socket.emit('chat message',$('#m').val());
socket.emit('stop typing');
typing = false;
$('#m').val('');
return false;
});
$('#m').keyup(function(){
updateTyping();
});
socket.on('online num',function(msg){
$('#onlineshow').text('当前在线'+msg+'人');
});
socket.on('join', function (msg) {
$('#joinshow').text(msg.ip+'增加');
});
socket.on('typing',function(msg){
typingIps[msg.ip]=msg.ip;
var typingArr=[];
for(var ip in typingIps){
typingArr.push(typingIps[ip]);
}
$('#typingshow').text(typingArr.join(',') + '正在输入...');
});
socket.on('stop typing',function(msg){
delete typingIps[msg.ip];
var typingArr=[];
for(var ip in typingIps){
typingArr.push(typingIps[ip]);
}
if(typingArr.length===0){
$('#typingshow').text('');
}else{
$('#typingshow').text(typingArr.join(',') + '正在输入...');
}
});
socket.on('chat message', function(msg){
$('#messages').append($('<li>').text(msg.ip+'说:'+msg.content));
});
socket.on('user left', function(msg){
$('#leftshow').text(msg.ip+'离开了');
$('#onlineshow').text('当前在线'+msg.onlineNum+'人');
});
</script>
</body>
</html>/**
* Created by luzhen on 14-11-10.
*/
var express = require('express');
var app=express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var ips={};
app.use(express.static(__dirname + '/public'));
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
var onlineNum=0;
io.on('connection', function (socket) {
console.log(socket.request.connection.remoteAddress);
ips[socket.request.connection.remoteAddress]=socket.request.connection.remoteAddress;//clientip
//socket.handshake.address 服务端ip
onlineNum++;
socket.broadcast.emit('join', {'ip':socket.request.connection.remoteAddress});//广播新用户增加
io.emit('online num',onlineNum);//广播当前在线人数
socket.on('chat message', function (msg) {
io.emit('chat message', {ip:socket.request.connection.remoteAddress,'content':msg});
console.log('message: ' + msg);
});
socket.on('typing', function (msg) {
socket.broadcast.emit('typing', {'ip':socket.request.connection.remoteAddress});
});
socket.on('stop typing', function (msg) {
socket.broadcast.emit('stop typing', {'ip':socket.request.connection.remoteAddress});
});
socket.on('disconnect',function(){
delete ips[socket.request.connection.remoteAddress];
onlineNum--;
socket.broadcast.emit('user left', {'ip':socket.request.connection.remoteAddress,'onlineNum':onlineNum});
});
});
http.listen(3000, function () {
console.log('listening on *:3000');
});新增了防止刷屏功能,完整代码开源在GitHub上。
Demo演示 查看效果
原文:http://www.cnblogs.com/tlnshuju/p/7172356.html