web编程期末树莓派项目(四)——websocket实现聊天室

聊天室

效果展示

  • 微型登陆页面
    在这里插入图片描述
  • 聊天页面
    在这里插入图片描述
  • 手机端显示
    在这里插入图片描述
    在这里插入图片描述

websocket

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
在这里插入图片描述

前端实现

html语句只能实现非常简单的页面,重点在于css的渲染

登陆页面

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.1/css/all.min.css"
integrity="sha256-mmgLkCYLUQbXn0B1SRqzHar6dCnv9oZFPEC1g1cwlkk="
crossorigin="anonymous"
/>
<link rel="stylesheet" href="css/style.css" />
<title>聊天室</title>
</head>
<body>
<div class="join-container">
<header class="join-header">
<h1><i class="fa fa-comments"></i> 聊天室</h1>
</header>
<main class="join-main">
<form action="chat.html">
<div class="form-control">
<label for="username">账户</label>
<input
type="text"
name="username"
id="username"
placeholder="输入用户名"
required
/>
</div>
<div class="form-control">
<label for="room">房间</label>
<select name="room" id="room">
<option value="philca的房间">philca的房间</option>
</select>
</div>
<button type="submit" class="btn">加入聊天室</button>
</form>
</main>
</div>
</body>
</html>

聊天页面

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.1/css/all.min.css"
integrity="sha256-mmgLkCYLUQbXn0B1SRqzHar6dCnv9oZFPEC1g1cwlkk="
crossorigin="anonymous"
/>
<link rel="stylesheet" href="css/style.css" />
<title>聊天室</title>
</head>
<body>
<div class="chat-container">
<header class="chat-header">
<h1><i class="fa fa-globe"></i> 聊天室</h1>
<a id="leave-btn" class="btn">离开房间</a>
</header>
<main class="chat-main">
<div class="chat-sidebar">
<h3><i class="fas fa-comments"></i> 房间名</h3>
<h2 id="room-name"></h2>
<h3><i class="fas fa-users"></i> 用户</h3>
<ul id="users"></ul>
</div>
<div class="chat-messages"></div>
</main>
<div class="chat-form-container">
<form id="chat-form">
<input
id="msg"
type="text"
placeholder="输入信息"
required
autocomplete="off"
/>
<button class="btn"><i class="fas fa-paper-plane"></i> 发送</button>
</form>
</div>
</div>

<script
src="https://cdnjs.cloudflare.com/ajax/libs/qs/6.9.2/qs.min.js"
integrity="sha256-TDxXjkAUay70ae/QJBEpGKkpVslXaHHayklIVglFRT4="
crossorigin="anonymous"
></script>
<script src="/socket.io/socket.io.js"></script>
<script src="js/main.js"></script>
</body>
</html>

后端实现

将后端分为几个模块

消息传输

1
2
3
4
5
6
7
8
9
10
11
const moment = require('moment');

function formatMessage(username, text) {
return {
username,
text,
time: moment().format('h:mm:ss a')
};
}

module.exports = formatMessage;

以此来显示用户身份、消息内容、消息发送时间
在这里插入图片描述

用户行为

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
const users = [];

function userJoin(id, username, room) {
const user = { id, username, room };

users.push(user);

return user;
}

function getCurrentUser(id) {
return users.find(user => user.id === id);
}

function userLeave(id) {
const index = users.findIndex(user => user.id === id);

if (index !== -1) {
return users.splice(index, 1)[0];
}
}
function getRoomUsers(room) {
return users.filter(user => user.room === room);
}

module.exports = {
userJoin,
getCurrentUser,
userLeave,
getRoomUsers
};

用于判断用户加入的房间,加入房间、离开房间的行为

整体运行

需要引入socket.io模块,作用是实现服务器端与客户端的长连接

1
const socketio = require('socket.io');

规定在3000端口显示

1
2
3
const PORT = process.env.PORT || 3000;

server.listen(PORT, () => console.log(`Server running on port ${PORT}`));