写了一个socket.io服务,实现了用户区分、公聊、私聊等。。。
码云地址https://gitee.com/liuoomei/so…
app.js
//app.js
var express = require('express')
var app = express();
var server = require('http').Server(app);
// var io = require('socket.io')(server);
var path = require('path');
app.use(express.static(path.join(__dirname, 'public')))
app.get('/', function(req, res){
res.sendFile(path.join(__dirname, 'index.html'));
});
module.exports = app;
bin/www
#!/usr/bin/env node
/**
* Module dependencies.
*/
let app = require('../app');
let debug = require('debug')('mysocket:server');
let http = require('http');
let _ = require('underscore');
/**
* Get port from environment and store in Express.
*/
let userLs = []
let port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
let server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
let io = require('socket.io')(server);
io.on('connection', function(socket){
socket.on('login', function(userid){
let obj = {
userid,
id: socket.id
}
userLs.push(obj)
console.log(userid + '建立了链接');
socket.emit('userLs',userLs)
socket.emit('login',socket.id)
});
// 判断用户离线事件可以通过socket.io自带的disconnect事件完成,当一个用户断开连接,disconnect事件就会触发
socket.on('disconnect', function(){
let _user = _.where(userLs,{id:socket.id})
console.log('_user',_user)
console.log(socket.id + '中断了链接');
userLs = userLs.filter(it =>{
return _user.every(item =>{
return it.id != item.id
})
})
// do somethings
console.log('del',userLs)
});
socket.on('message', function (data) {
//服务端像所以也没发送数据
let _user = _.where(userLs,{id:socket.id})
io.sockets.emit('message', {id:_user[0].id,userid:_user[0].userid,message:data.message}); //给所有人(包括自己)发送消息
// socket.broadcast.emit('message', data.message); //给所有人(不包括自己)发送消息
});
socket.on('sayTo', function (data) {
let toMsg = data.message;
let toId = data.id;
// nodejs的underscore扩展中的findWhere方法,可以在对象集合中,通过对象的属性值找到该对象并返回。
let _user = _.where(userLs,{id:toId})
if(_user){
let toSocket = _.findWhere(io.sockets.sockets, {id: toId});
// 通过该连接对象(toSocket)与链接到这个对象的客户端进行单独通信
socket.emit('message', {id:socket.id,message:toMsg}) //向建立该连接的客户端广播
toSocket.emit('message', {id:socket.id,message:toMsg});
}else{
socket.emit('error','该用户不在线')
}
// socket.emit() :向建立该连接的客户端广播
// socket.broadcast.emit() :向除去建立该连接的客户端的所有客户端广播
// io.sockets.emit() : 向所有客户端广播,等同于上面两个的和
});
});
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
let port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
let bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
let addr = server.address();
let bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
console.log(`服务已启动,端口:${addr.port}`)
}
public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.chat{
width: 300px;
height: 500px;
text-align: center;
margin: 0 auto;
border: 1px solid #ccc;
}
.message{
width: 100%;
height: 460px;
}
#table{
border: 1px solid
}
</style>
</head>
<body>
<div class="chat">
<select name="" id="select" onchange="console.log()">
</select>
<div class="message"></div>
<div>我是<span id="_id"></span></div>
<input id="text" type="text" placeholder="请输入聊天信息">
<button onclick="chat()">发送信息</button>
</div>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<!-- 这里socket不需要引用外部文件,node后台运行会自动生成可以引用的js文件 -->
<!-- <script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.js"></script> -->
<script src="/socket.io/socket.io.js"></script>
<!-- <script src="./javascripts/underscore.min.js"></script> -->
<script>
let message = document.getElementsByClassName('message')[0]
let socket = io.connect('http://localhost:3000');
//
let userid = this.getUuid()
let userLs = []
socket.emit('login', userid);
//从服务端接收数据
socket.on('login',function (data) {
document.getElementById("_id").innerHTML = data;
})
socket.on('message',function (data) {
message.innerHTML += `${data.id}:${data.message}` + '<br>';
})
socket.on('sayTo',function (data) {
message.innerHTML += `${data.id}:${data.message}` + '<br>';
})
socket.on('userLs',function (data) {
console.log(data)
$("#select").append(`<option value="">所有人</option>`)
if(data.length > 0){
for(let item of data){
$("#select").append(`<option value="${item.id}">${item.id}</option>`)
}
}
})
socket.on('error', function(msg) {
//错误提示
alert(msg)
});
function chat(){
let text = document.getElementById('text').value
if(!text){
alert('不能发送空消息!')
return
}
//向服务端发送数据
if($('#select option:selected').val()){
console.log($('#select option:selected').val())
// return
socket.emit('sayTo', {id:$('#select option:selected').val(),message:text});
}else{
socket.emit('message', {message:text});
}
}
function getUuid () {
function S4 () {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
}
return (S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4())
}
</script>
</body>
</html>