【work记录:c++web聊天服务器】修复多个客户端登录重复的bug|更新单个客户端退出功能|调整好友列表和群聊列表的代码
日期:2025.4.21
学习内容:
- 整理前端代码
- 修复多个客户端登录重复的bug
- 更新单个客户端退出功能
- 更新好友列表与群聊列表的交互按钮
- 调整好友列表和群聊列表的代码
个人总结:
整理前端代码:
是这样的,之前对于这些东西完全不太怎么了解,让AI直接跑出来,自己做一些简单的修改操作,但是现在实在是不行了。
我的脑子看到这几百行的代码就已经要废掉了,感觉功能什么的,已经完全加不下去了,于是决定整理一下。

大概就是长这个样子,其实就和之前写C++后端的时候差不太多,果然大家都是差不多的。
然后这里js的文件夹里面都是对于index.html的文件:
- handler.js:做接受消息处理器的,主要功能实现在这里面
- config.js:目前有点鸡肋,放一些消息的定义
- websocket.js:把websocket的一些操作封装了起来,我们以后调用ws.send的时候都是默认发送JSON文件了。
- main.js: 所有的入口,做一些客户端的操作的功能
更新了mudule模块
将原本的main.js里的sendMessage的模块挪到了一个mudule文件夹下,在websocket类里修改了两个函数,send和sendByJson函数。
前者是直接用来发送数据,后者是发送json数据用的。
修复bug
真的,卡了我好久,结果一个很简单的sessionStorage就解决了。
问题是这样的:因为我用了localStorage,导致我如果浏览器连续开两个客户端,第二个客户端在刷新的时候就会读取到最新的客户登录的信息,然后我问了弱智AI,
AI给了我个弱智回复,然后我竟然一开始还不带脑子照着那个去实现了半天,大概的意思就是实现两个localStorage,一个存储当前活跃用户信息,一个就像是map一样去实现,结果我发现还是不行,然后又开了个新窗口问AI,AI告诉我有sessionStorage这个东西的存在,也就是说可以不用存储到本地上,而是存储到当前的标签页上,于是就非常丝滑的解决了这个问题。
日期:2025.4.22
个人总结:
更新退出功能
之前一直懒,写了一个把所有客户端强制退出,方便服务器这边做一些测试之类的,但是现在既然写了一个前端,那么就完善一下退出功能。

左下角这里加了一个退出按钮,当点击退出按钮的时候,将向服务端发送一个退出的消息,接收到了退出允许的消息的话,就会与服务端断开连接,同时跳转到登录页面。
export function logout() {
// 构造消息对象
const message = {
msgid: 17,
user_id: parseInt(storedUser.id)
};
// 发送到服务器
ws.sendByJson(message);
}
main.js:
// 执行 退出登录 功能, 当点击按钮的时候
const logoutButton = document.getElementById("logout-btn");
logoutButton.addEventListener("click", logout);
同时服务端那边也做了一些更新:
void ChatService::CloseUser(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
int user_id = js["user_id"].get<int>();
auto it = _conn_mp.find(user_id);
if (it != _conn_mp.end())
{
auto session = it->second;
json response;
response["user_id"] = user_id;
response["msgid"] = CLOSE_USER_MSG_ACK;
response["uid"] = session.getUid();
Send(conn, response.dump());
_conn_mp.erase(it);
User user;
user.SetID(user_id);
_user_modle.UpdateState(user, "offline");
_redis.UnSubscribe(user.GetID());
}
}
其实就是一些很弱智的操作了,没有什么高端的,纯纯苦力,活成了java的样子。
更新好友列表与群聊列表的交互按钮

具体看图,现在左边这两个按钮可以点击了,点击之后会切换到对应的好友列表和群聊列表。(讲真的这一块好恶心)我果然还是不喜欢前端。
另外我突然意识到了一个bug:
关于我右边的聊天窗口,原来是没有与点击好友关联的。也就是说其实现在更像是一个聊天室项目了。。。
所以后续要补的bug之一,就是要完善好这个聊天窗口,阿巴阿巴业务好恶心。更多的内容到调整好友列表和群聊列表的代码去讲了。
调整好友列表和群聊列表的代码
首先先看handler的改动:
15: (data) => {
// 1. 解析数据
const parsedFriends = data.friends.map(friendStr => JSON.parse(friendStr));
const parsedGroups = data.groups.map(friendStr => JSON.parse(friendStr));
// 2. 更新存储(重要!)
parsedFriends.forEach(friend => {
appState.friends.set(friend.id, friend);
});
parsedGroups.forEach(group => {
appState.groups.set(group.id, group);
});
// 3. 如果当前显示的是好友列表
if (appState.currentView === 'friends') {
friendListView.handle();
}
else {
// 3. 如果当前显示的是群聊列表
GroupListView.handle();
}
},
这里之前是写了一坨,现在我们写了一个关于friendListView的类,然后把那些渲染之类的操作放到了类里面,现在这里做一些存储数据的功能。
存储数据:这里简单提一下,之前我们是直接获取到了parsedFriends,然后直接对他进行解析,对于解析的内容直接呈现到了web上,所以我们并没有存储数据到浏览器里,也就是说我们如果后续做了一些页面切换(虽然我们并不会那样做)的操作,那我们这个页面回来的时候是不会有好友列表的,因为我们都没有存储起来呀!
所以这里关于申请自身状态的函数,做的改动就是把解析的数据存储起来,然后对于当前选择的数据分类讨论去渲染,渲染也是在各自的类里就去封装好的。
然后这里两个类长得极像,我并不想把他们融合成一个,然后通过type去分开区别,觉得这样其实更直观一些,于是就直接开了两个类。
import {appState} from './main.js'
export class FriendListHandler {
constructor(containerId, onFriendSelected) {
this.container = document.getElementById(containerId);
// 好友选中回调函数
this.onFriendSelected = onFriendSelected;
}
// 核心消息处理方法
handle() {
if (appState.currentView === 'friends') {
this._renderList(Array.from(appState.friends.values()));
}
this._bindItemClickEvents();
}
// 渲染好友列表(私有方法)
_renderList(friends) {
// console.log("解析了");
this.container.innerHTML = friends.map(friend => `
<div class="list-item"
data-id="${friend.id}"
data-name="${friend.name}"
data-state="${friend.state}">
<div>
<div>${friend.name}</div>
<div style="color: #666; font-size: 0.9em">
${this._getStateText(friend.state)}
</div>
</div>
<div class="status-indicator ${friend.state === 'online' ? 'online' : ''}"></div>
</div>
`).join('');
}
// 获取状态文本(私有方法)
_getStateText(state) {
return state === 'online' ? '在线' : '离线';
}
// 绑定点击事件(私有方法)
_bindItemClickEvents() {
this.container.querySelectorAll('.list-item').forEach(item => {
item.addEventListener('click', () => {
// 清除所有激活状态
this._clearActiveStates();
// 设置当前激活项
item.classList.add('active');
// 触发回调
this.onFriendSelected({
id: item.dataset.id,
name: item.dataset.name,
state: item.dataset.state
});
});
});
}
// 清除激活状态(私有方法)
_clearActiveStates() {
this.container.querySelectorAll('.list-item').forEach(item => {
item.classList.remove('active');
});
}
}
这里的注释其实写的也算是比较详细了,不得不说AI挺好的 (不知道刚才谁骂了sbAI
另外说一句题外话:如果我现在还想要一些新功能,例如之前提到的申请好友之类的,我觉得对我更大的挑战在于是前端的实现,就像今天和昨天,其实基本上我都是在前端上花费了很多的时间,所以我觉得应该刨去一些那些功能,实现一些关键的内容,这样我才说不定可以赶上下个月中旬之前完成。
所以现在主要是打算实现好web的基本功能,然后去好好搞后端。
来总结一下目前的bug:
- 没有区分好友或者群聊的聊天窗口
- 聊天窗口并不会收缩,如果聊天消息多会直接伸长。
- 没有实现群聊聊天功能(web)
- 状态没有自动刷新
功能方面所欠缺的:
- 离线消息
- 历史消息

浙公网安备 33010602011771号