【work记录:c++web聊天服务器】实现了基本聊天功能|修复muduo服务器的部分bug|前端页面设计
日期:2025.4.21(凌晨)
学习内容:
- 修复了muduo服务端重复利用
CHAT_ONE_MSG的bug - 实现了基本的聊天功能
个人总结:
自上一篇之后,又摸鱼吭哧吭哧了半天。
这次实现了基本的聊天功能,先贴一张图,然后聊一下大致的改进如下:

修复muduo服务器的Msgtype
之前为了偷工减料,没有设置发送消息MSG的ACK,导致发送的消息无法判断是自己发送的还是对方发送的(其实也是可以的,只需要判断一下to_id是不是自己的id就好了),但是还是觉得要加上才算是比较完善一点的,起码看起来比较好一点(bushi
enum Msgtype
{
LOGIN_MSG = 1, // 1 登录的msg
LOGIN_MSG_ACK, // 2 响应登录的msg ack
REG_MSG, // 3 注册的msg
RES_MSG_ACK, // 4 响应注册的msg ack
CHAT_ONE_MSG, // 5 跟一个人发消息的msg
ADD_FRIEND_MSG, // 6 向一个人添加好友的msg
CREAT_GROUP_MSG, // 7 创建一个群聊的msg
ADD_GROUP_MSG, // 8 添加一个群聊的msg
CHAT_GROUP_MSG, // 9 在群聊里发消息的msg
LOGIN_NAME_MSG, // 10 按照用户名登录的msg
ADD_FRIEND_MSG_ACK, // 11 向一个人添加好友的msg的ack
ADD_GROUP_MSG_ACK, // 12 添加一个群聊的msg的ack
CREATE_GROUP_MSG_ACK, // 13 创建一个群聊的msg的ack
SHOW_STATUS_MSG, // 14 请求自己状态的msg
SHOW_STATUS_MSG_ACK, // 15请求自己状态的msg的ack
CHAT_ONE_MSG_ACK, // 16跟一个人发送消息的msg的ack(收到消息的人会得到的ack)
};
这里贴一下Msgtype,估计后续还是会有更新。
修复了muduo服务器中ChatToOne函数:
我竟然发现之前实现的时候偷懒,直接利用了发送过来的json再发送回去。顺便把msgid也改成了新添加的CHAT_ONE_MSG_ACK。
void ChatService::ChatToOne(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
int to_id = js["to_id"].get<int>();
User to_user;
to_user = _user_modle.Query(to_id);
json response;
response["from_id"] = js["from_id"].get<int>();
response["from_name"] = js["from_name"].get<std::string>();
response["to_id"] = to_id;
response["msgid"] = CHAT_ONE_MSG_ACK;
response["text"] = js["text"];
response["time"] = js["time"];
// 对方不在线
if (to_user.GetState() == "offline")
{
_offline_msg_model.Insert(to_id, response.dump());
return;
这里关于response的内容是我今天刚补上的。
另外还有上一篇中短暂提到的ShowStatus函数的修改,也在本篇中展示一下:
void ChatService::ShowStatus(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
int user_id = js["user_id"].get<int>();
User user;
user.SetID(user_id);
json response;
std::string uid = js["uid"].get<std::string>();
Session session(conn, uid);
ConnInsert(user_id, session);
然后后续的改动其实更多的地方在客户端多一些了。
算是大概得了解了一下客户端的写法,虽然自己还是写不出来,但是多多少少能看懂一点点了。
关于发送消息的代码:
// 发送消息功能
const messageInput = document.getElementById("message-input");
const sendButton = document.getElementById("send-button");
sendButton.addEventListener("click", sendMessage);
messageInput.addEventListener("keydown", (e) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
sendMessage();
}
});
function sendMessage() {
const content = messageInput.value.trim();
// console.log("111");
if (!content || !currentChat) {
// if (!currentChat) console.log("333");
// if (!content) console.log("444");
return;
}
// console.log("222");
// 构造消息对象
const message = {
msgid: 5,
from_name: storedUser.name,
from_id: parseInt(storedUser.id),
to_id: parseInt(currentChat.id),
text: content,
time: new Date().toLocaleString(),
};
const message_to_self = {
msgid: 5,
from_name: storedUser.name,
from_id: parseInt(storedUser.id),
to_id: parseInt(storedUser.id),
text: content,
time: new Date().toLocaleString(),
};
// 立即显示本地消息
messageHandlers[16](message_to_self);
// 发送到服务器
ws.send(JSON.stringify(message));
// 清空输入框
messageInput.value = "";
}
还有其实对我来说感觉比较新颖的是这一段(处理好友列表的内容)
// 处理好友列表
15: (data) => {
// console.log("收到好友列表数据:", data);
const friendsList = document.getElementById("friends-list");
const parsedFriends = data.friends.map((friendStr) =>
JSON.parse(friendStr)
);
friendsList.innerHTML = parsedFriends
.map(
(friend) => `
<div class="list-item" data-id="${friend.id}" data-name="${
friend.name
}">
<div>
<div >${friend.name}</div>
<div style="color: #666; font-size: 0.9em">${
friend.state === "online" ? "在线" : "离线"
}</div>
</div>
<div class="status-indicator ${
friend.state === "online" ? "online" : ""
}"></div>
</div>
`
)
.join("");
// 添加好友点击事件
friendsList.querySelectorAll(".list-item").forEach((item) => {
item.addEventListener("click", () => {
// 移除其他项的激活状态
document
.querySelectorAll(".list-item")
.forEach((i) => i.classList.remove("active"));
item.classList.add("active");
// 更新当前聊天对象
currentChat = {
type: "friend",
id: item.dataset.id,
name: item.dataset.name,
};
// 更新聊天窗口标题
document.querySelector(
".chat-header"
).textContent = `与 ${currentChat.name} 的对话`;
// TODO: 加载历史消息
});
});
},
这里对于前端的代码就不细说了,我还是小白,目前只是勉强能用的状态。
后续问题:
来说说后续:
现在首先有一个问题就是之前客户端做到的,目前还没有处理的内容:
- 离线消息
- 群聊
- 申请添加好友
- 状态刷新
现在我觉得都好麻烦啊,一想到还有前端要整就感觉好ex。自己会有时间搞定吗?还有八股要背,我目前是一点没看。
目前有一些暂时不太能想明白的就是关于这个状态刷新,虽然说websocket协议现在是长连接了,但是我的状态刷新还是得从服务端发送过来才可以呢。目前暂时考虑的一个方案就是每当自己有一个好友上线了,就会向他的好友们去发送一个状态刷新,这样就能即时知道了好友的在线情况。但是这样做我觉得又会比较的浪费性能资源,如果节约一点,可能就要考虑上用户的常聊角色,或者是最近聊天的角色,先只刷新这些好友的状态。又或者是直接从列表上删除好友的在线状态(不是,然后点开一个好友的窗口,再发送一个是否在线的请求。这样做性能上讲应该浪费的就不多了,不过代码量倒是又多了不少。
另外还有历史消息的存储,传输文件等内容,感觉还有好长的一段路要走,而且这样做的话,感觉这个项目很大程度上已经变成了一个java项目233,貌似感觉作用不是太大的样子。w先睡了吧还是,明天还有课要上,好像过两天就是小组作业了,我还啥都不知道阿巴阿巴

浙公网安备 33010602011771号