websocket打造简易聊天室

这两天看了下关于websocket方面的东西,现代浏览器基本都支持websocket,这样可以很方便实现双向的通信。然后简单写了一个聊天室

简单说明下websocket与http,个人理解两者都是在传输层TCP之上的实现方式。HTTP是客户端向服务器发送请求,服务器接收到请求,然后回应客户端,发送数据,但是服务器端不能够主动发送请求让客户端接受信息,这时候,就需要websocket了。简单地说,区别就是服务器端能主动与客户端通信。

websocket

简单入门

廖雪峰的websocket教程
介绍了websocket的基本使用方法

socket.io

socket.io是对websocket的一层封装,准确的说还加入了ajax功能,帮助不支持websocket的浏览器实现接近websocket的功能

聊天室的实现

有了socketio,就能够很方便实现,数据的分发,然后这里使用的是koa2作为后台。

socketio事件处理部分

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
io.attach( app )

io.on('connection', (ctx, data) => {
let room = url.parse(ctx.socket.request.headers.referer).pathname.substr(1);
logger.info(`a user connected to room: ${room}`)

ctx.socket.on('join',(username) => {
console.log(username)
ctx.socket.join(room);
if (!userObj[ctx.socket.id]) {
userObj[ctx.socket.id] = username
}
if (!roomObj[room]) {
roomObj[room] = []
roomObj[room].push(ctx.socket.id)
} else {
roomObj[room].push(ctx.socket.id)
}
io.broadcast( 'message', {user:'系统',content:`欢迎 ${username} 进入房间 ${room} 当前在线人数:${io.connections.size}`} );
io.to(room).emit( 'message', {user:'系统',content:`欢迎 ${username} 进入了该房间 该房间人数${ roomObj[room].length}`});
});
});

io.on('disconnect',(ctx, data) =>{
logger.warn(`user: ${userObj[ctx.socket.id]} disconnected`);
io.broadcast( 'message', {user:'系统',content: `用户 ${userObj[ctx.socket.id]} 下线了`});
for (let item in roomObj) {
if (roomObj[item].indexOf(ctx.socket.id) >= -1) {
roomObj[item].splice(item.indexOf(ctx.socket.id), 1)
}
}
delete userObj[ctx.socket.id]
});

io.on('message', (ctx, data) => {
let rooms = []
for (let item in ctx.socket.rooms) {
rooms.push(item)
}
logger.info('receive a message ' + data);
io.to(rooms[0]).emit( 'message', {user:userObj[ctx.socket.id],content:data});
});

处理socket的事件,并且维护用户列表以及房间的用户列表

聊天室前端部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
app.use(require('koa-static')(__dirname + '/public'))

router.get('/:roomid', async (ctx, next) => {
const readFile = promisify(fs.readFile)
try {
let ret = await readFile(__dirname+'/public/room.html', 'utf8')
ctx.body = ret;
} catch (err) {
console.log(err)
ctx.throw(500, err)
}
});

app.use(router.routes(), router.allowedMethods())

前端部分就两个页面 一个是首页,直接使用koa-static实现,房间页面通过路由匹配发送给客户端。

项目托管地

实现效果

01

02

03