废弃的聊天室代码

😭😭😭
This commit is contained in:
zsyg
2025-07-07 20:34:34 +08:00
committed by GitHub
parent 837aba38ba
commit 280a9122b9
29 changed files with 1192 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
#include "Application.hpp"
#include "MainWindow.hpp"
#include <FL/Fl.H>
#include <iostream>
Application::Application(int argc, char** argv)
: mainWindow(nullptr) {
try {
std::cout << "正在初始化应用程序..." << std::endl;
mainWindow = new MainWindow(400, 300, "局域网聊天室");
std::cout << "主窗口创建成功" << std::endl;
} catch (const std::exception& e) {
std::cerr << "初始化失败: " << e.what() << std::endl;
}
}
int Application::run() {
std::cout << "应用程序启动..." << std::endl;
if (!mainWindow) {
std::cerr << "致命错误: 主窗口对象创建失败" << std::endl;
return 1;
}
try {
std::cout << "初始化FLTK图形界面..." << std::endl;
Fl::scheme("gtk+");
std::cout << "显示主窗口..." << std::endl;
mainWindow->show();
std::cout << "窗口尺寸: " << mainWindow->w() << "x" << mainWindow->h() << std::endl;
std::cout << "进入主事件循环..." << std::endl;
int ret = Fl::run();
std::cout << "应用程序正常退出" << std::endl;
return ret;
} catch (const std::exception& e) {
std::cerr << "运行时错误: " << e.what() << std::endl;
return 1;
}
}
Application::~Application() {
delete mainWindow;
}

View File

@@ -0,0 +1,104 @@
#include "ChatRoom.hpp"
#include "Message.hpp"
#include "MessageProtocol.hpp"
#include <iostream>
#include <algorithm>
#include <winsock2.h>
#include <ws2tcpip.h>
ChatRoom::ChatRoom() : network(std::make_unique<NetworkManager>()) {}
ChatRoom::~ChatRoom() {}
bool ChatRoom::createRoom(int port, const std::string& password) {
roomPassword = password;
if (!network->startServer(port)) {
std::cerr << "Failed to create room on port " << port << std::endl;
return false;
}
return true;
}
bool ChatRoom::joinRoom(const std::string& ip, int port, const std::string& password) {
if (!network->connectToServer(ip, port)) {
std::cerr << "Failed to connect to " << ip << ":" << port << std::endl;
return false;
}
// 发送密码验证
Message authMsg(nullptr, password, MessageType::AUTH);
network->sendMessage(MessageProtocol::encodeMessage(authMsg));
// 等待验证响应
auto response = network->receiveMessages();
if (response.empty() || response[0] != "AUTH_SUCCESS") {
return false;
}
return true;
}
std::string ChatRoom::getRoomPassword() const {
return roomPassword;
}
std::string ChatRoom::getLocalIP() const {
char host[256];
if (gethostname(host, sizeof(host)) == SOCKET_ERROR) {
return "127.0.0.1";
}
struct hostent* phe = gethostbyname(host);
if (phe == nullptr) {
return "127.0.0.1";
}
for (int i = 0; phe->h_addr_list[i] != nullptr; ++i) {
struct in_addr addr;
memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr));
std::string ip = inet_ntoa(addr);
if (ip != "127.0.0.1") {
return ip;
}
}
return "127.0.0.1";
}
void ChatRoom::sendChatMessage(const std::string& message) {
network->sendMessage(message);
messages.push_back(message);
}
void ChatRoom::addUser(const std::string& username) {
auto user = std::make_shared<User>(username, "");
users.push_back(user);
}
void ChatRoom::removeUser(const std::string& username) {
users.erase(
std::remove_if(users.begin(), users.end(),
[&username](const std::shared_ptr<User>& user) {
return user->getUsername() == username;
}),
users.end());
}
const std::vector<std::string>& ChatRoom::getMessages() const {
return messages;
}
const std::vector<std::shared_ptr<User>>& ChatRoom::getUsers() const {
return users;
}
std::string ChatRoom::getCurrentUsername() const {
if (!users.empty()) {
return users[0]->getUsername();
}
return "";
}
NetworkManager* ChatRoom::getNetworkManager() const {
return network.get();
}

View File

@@ -0,0 +1,50 @@
#include "ChatWindow.hpp"
#include <FL/Fl.H>
#include <iostream>
ChatWindow::ChatWindow(int w, int h, const char* title, std::shared_ptr<ChatRoom> chatRoom)
: Fl_Window(w, h, title), chatRoom(chatRoom) {
// 设置消息回调
auto networkManager = chatRoom->getNetworkManager();
networkManager->setMessageCallback([this](const std::string& msg) {
this->appendMessage(msg);
});
messageBuffer = new Fl_Text_Buffer();
messageDisplay = new Fl_Text_Display(20, 20, w-220, h-70);
messageDisplay->buffer(messageBuffer);
userList = new Fl_Browser(w-190, 20, 170, h-70);
userList->type(FL_MULTI_BROWSER);
messageInput = new Fl_Input(20, h-40, w-100, 30);
sendButton = new Fl_Button(w-70, h-40, 60, 30, "发送");
sendButton->callback(onSendMessageCallback, this);
updateUserList();
}
void ChatWindow::appendMessage(const std::string& message) {
messageBuffer->append(message.c_str());
messageBuffer->append("\n");
messageDisplay->scroll(messageBuffer->count_lines(0, messageBuffer->length()), 0);
}
void ChatWindow::updateUserList() {
userList->clear();
for (const auto& user : chatRoom->getUsers()) {
userList->add(user->getUsername().c_str());
}
}
void ChatWindow::onSendMessageCallback(Fl_Widget* w, void* data) {
ChatWindow* win = static_cast<ChatWindow*>(data);
std::string message = win->messageInput->value();
if (!message.empty()) {
win->chatRoom->sendChatMessage(message);
win->messageInput->value("");
Fl::focus(win->messageInput);
}
}

View File

@@ -0,0 +1,38 @@
#include "ConfigManager.hpp"
#include <fstream>
#include <sstream>
ConfigManager& ConfigManager::getInstance() {
static ConfigManager instance;
return instance;
}
void ConfigManager::loadConfig(const std::string& filename) {
std::ifstream file(filename);
std::string line;
while (std::getline(file, line)) {
size_t pos = line.find('=');
if (pos != std::string::npos) {
std::string key = line.substr(0, pos);
std::string value = line.substr(pos + 1);
configMap[key] = value;
}
}
}
void ConfigManager::saveConfig(const std::string& filename) {
std::ofstream file(filename);
for (const auto& pair : configMap) {
file << pair.first << "=" << pair.second << "\n";
}
}
std::string ConfigManager::getValue(const std::string& key) {
return configMap[key];
}
void ConfigManager::setValue(const std::string& key, const std::string& value) {
configMap[key] = value;
}

View File

@@ -0,0 +1,140 @@
#include "MainWindow.hpp"
#include "ChatWindow.hpp"
#include <FL/Fl_Input.H>
#include <FL/Fl_Output.H>
#include <iostream>
#include <string>
MainWindow::MainWindow(int w, int h, const char* title)
: Fl_Window(w, h, title), chatRoom(std::make_unique<ChatRoom>()) {
// 初始化窗口基础属性
color(FL_WHITE);
begin();
try {
// 初始化界面组件
titleBox = new Fl_Box(w/2-100, 20, 200, 30, "局域网聊天室");
titleBox->box(FL_NO_BOX);
titleBox->labelfont(FL_BOLD);
titleBox->labelsize(20);
titleBox->labelcolor(FL_BLUE);
createRoomBtn = new Fl_Button(w/2-100, 100, 200, 40, "创建房间");
createRoomBtn->callback(onCreateRoomCallback, this);
joinRoomBtn = new Fl_Button(w/2-100, 160, 200, 40, "加入房间");
joinRoomBtn->callback(onJoinRoomCallback, this);
// 初始化对话框指针
createRoomDialog = nullptr;
joinRoomDialog = nullptr;
usernameDialog = nullptr;
end();
} catch (const std::exception& e) {
std::cerr << "窗口初始化失败: " << e.what() << std::endl;
throw;
}
}
MainWindow::~MainWindow() {
if (createRoomDialog) delete createRoomDialog;
if (joinRoomDialog) delete joinRoomDialog;
if (usernameDialog) delete usernameDialog;
}
void MainWindow::showCreateRoomDialog() {
if (createRoomDialog) return;
createRoomDialog = new Fl_Window(300, 250, "创建房间");
createRoomDialog->begin();
portInput = new Fl_Input(100, 30, 180, 30, "端口:");
passwordInput = new Fl_Input(100, 70, 180, 30, "密码:");
Fl_Button* confirmBtn = new Fl_Button(100, 120, 100, 30, "确认");
confirmBtn->callback(onCreateRoomConfirmCallback, this);
createRoomDialog->end();
createRoomDialog->show();
}
void MainWindow::showJoinRoomDialog() {
if (joinRoomDialog) return;
joinRoomDialog = new Fl_Window(300, 250, "加入房间");
joinRoomDialog->begin();
ipInput = new Fl_Input(100, 30, 180, 30, "IP地址:");
portInput = new Fl_Input(100, 70, 180, 30, "端口:");
passwordInput = new Fl_Input(100, 110, 180, 30, "密码:");
Fl_Button* confirmBtn = new Fl_Button(100, 160, 100, 30, "确认");
confirmBtn->callback(onJoinRoomConfirmCallback, this);
joinRoomDialog->end();
joinRoomDialog->show();
}
void MainWindow::showUsernameDialog() {
if (usernameDialog) return;
usernameDialog = new Fl_Window(300, 150, "输入用户名");
usernameDialog->begin();
usernameInput = new Fl_Input(100, 30, 180, 30, "用户名:");
Fl_Button* confirmBtn = new Fl_Button(100, 80, 100, 30, "确认");
confirmBtn->callback(onUsernameConfirmCallback, this);
usernameDialog->end();
usernameDialog->show();
}
void MainWindow::onCreateRoomCallback(Fl_Widget* w, void* data) {
MainWindow* win = static_cast<MainWindow*>(data);
win->showCreateRoomDialog();
}
void MainWindow::onJoinRoomCallback(Fl_Widget* w, void* data) {
MainWindow* win = static_cast<MainWindow*>(data);
win->showJoinRoomDialog();
}
void MainWindow::onCreateRoomConfirmCallback(Fl_Widget* w, void* data) {
MainWindow* win = static_cast<MainWindow*>(data);
int port = std::stoi(win->portInput->value());
std::string password = win->passwordInput->value();
if (win->chatRoom->createRoom(port, password)) {
win->createRoomDialog->hide();
win->showUsernameDialog();
}
}
void MainWindow::onJoinRoomConfirmCallback(Fl_Widget* w, void* data) {
MainWindow* win = static_cast<MainWindow*>(data);
std::string ip = win->ipInput->value();
int port = std::stoi(win->portInput->value());
std::string password = win->passwordInput->value();
if (win->chatRoom->joinRoom(ip, port, password)) {
win->joinRoomDialog->hide();
win->showUsernameDialog();
}
}
void MainWindow::onUsernameConfirmCallback(Fl_Widget* w, void* data) {
MainWindow* win = static_cast<MainWindow*>(data);
std::string username = win->usernameInput->value();
win->chatRoom->addUser(username);
win->usernameDialog->hide();
// 创建并显示聊天窗口
auto chatRoomPtr = std::shared_ptr<ChatRoom>(win->chatRoom.release());
auto chatWindow = new ChatWindow(800, 600, "聊天室", chatRoomPtr);
chatWindow->show();
// 隐藏主窗口
win->hide();
}

View File

@@ -0,0 +1,24 @@
#include "Message.hpp"
Message::Message(const std::shared_ptr<User>& sender,
const std::string& content,
MessageType type)
: sender(sender), content(content), type(type) {
timestamp = std::chrono::system_clock::now();
}
const std::shared_ptr<User>& Message::getSender() const {
return sender;
}
const std::string& Message::getContent() const {
return content;
}
MessageType Message::getType() const {
return type;
}
std::chrono::system_clock::time_point Message::getTimestamp() const {
return timestamp;
}

View File

@@ -0,0 +1,46 @@
#include "MessageProtocol.hpp"
#include <sstream>
#include "StringUtils.hpp"
std::string MessageProtocol::encodeMessage(const Message& message) {
std::ostringstream oss;
oss << static_cast<int>(message.getType()) << "|"
<< (message.getSender() ? message.getSender()->getUsername() : "") << "|"
<< message.getContent();
return oss.str();
}
Message MessageProtocol::decodeMessage(const std::string& data) {
auto parts = StringUtils::split(data, '|');
if (parts.size() < 3) {
throw std::runtime_error("Invalid message format");
}
std::shared_ptr<User> sender = nullptr;
if (!parts[1].empty()) {
sender = std::make_shared<User>(parts[1], "");
}
MessageType type = static_cast<MessageType>(std::stoi(parts[0]));
std::string content = parts[2];
if (type == MessageType::USER_JOIN || type == MessageType::USER_LEAVE) {
content = "";
}
return Message(sender, content, type);
}
bool MessageProtocol::validateMessage(const std::string& data) {
auto parts = StringUtils::split(data, '|');
if (parts.size() < 3) {
return false;
}
try {
int type = std::stoi(parts[0]);
return type >= 0 && type <= 5; // 检查消息类型是否有效(0-5对应MessageType枚举)
} catch (...) {
return false;
}
}

View File

@@ -0,0 +1,81 @@
#include "NetworkEventHandler.hpp"
#include <iostream>
#include <chrono>
#include "MessageProtocol.hpp"
NetworkEventHandler::NetworkEventHandler(std::shared_ptr<ChatRoom> chatRoom)
: chatRoom(chatRoom), running(false) {}
NetworkEventHandler::~NetworkEventHandler() {
stop();
}
void NetworkEventHandler::start() {
if (running) return;
running = true;
heartbeatThread = std::thread(&NetworkEventHandler::heartbeatCheck, this);
}
void NetworkEventHandler::stop() {
running = false;
if (heartbeatThread.joinable()) {
heartbeatThread.join();
}
}
void NetworkEventHandler::onConnected() {
auto users = chatRoom->getUsers();
if (!users.empty()) {
auto user = users[0]; // 假设第一个用户是当前用户
Message joinMsg(user, "", MessageType::USER_JOIN);
chatRoom->sendChatMessage(MessageProtocol::encodeMessage(joinMsg));
}
}
void NetworkEventHandler::onMessageReceived(const std::string& message) {
try {
if (!MessageProtocol::validateMessage(message)) {
return;
}
auto msg = MessageProtocol::decodeMessage(message);
switch (msg.getType()) {
case MessageType::TEXT_MESSAGE:
chatRoom->sendChatMessage(msg.getSender()->getUsername() + ": " + msg.getContent());
break;
case MessageType::USER_JOIN:
chatRoom->sendChatMessage(msg.getSender()->getUsername() + " 加入了聊天室");
break;
case MessageType::USER_LEAVE:
chatRoom->sendChatMessage(msg.getSender()->getUsername() + " 离开了聊天室");
break;
case MessageType::SYSTEM:
chatRoom->sendChatMessage("[系统] " + msg.getContent());
break;
case MessageType::AUTH:
if (msg.getContent() == chatRoom->getRoomPassword()) {
chatRoom->sendChatMessage("AUTH_SUCCESS");
} else {
chatRoom->sendChatMessage("AUTH_FAILED");
}
break;
default:
break;
}
} catch (const std::exception& e) {
std::cerr << "消息处理错误: " << e.what() << std::endl;
}
}
void NetworkEventHandler::onError(const std::string& error) {
chatRoom->sendChatMessage("[网络错误] " + error);
}
void NetworkEventHandler::heartbeatCheck() {
while (running) {
std::this_thread::sleep_for(std::chrono::seconds(30));
if (!chatRoom->getNetworkManager()->isConnected()) {
onError("连接已断开");
}
}
}

View File

@@ -0,0 +1,138 @@
#include "NetworkManager.hpp"
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <stdexcept>
#pragma comment(lib, "ws2_32.lib")
NetworkManager::NetworkManager() : serverSocket(INVALID_SOCKET), clientSocket(INVALID_SOCKET) {
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
throw std::runtime_error("WSAStartup failed");
}
}
NetworkManager::~NetworkManager() {
if (serverSocket != INVALID_SOCKET) {
closesocket(serverSocket);
}
if (clientSocket != INVALID_SOCKET) {
closesocket(clientSocket);
}
WSACleanup();
}
bool NetworkManager::startServer(int port) {
serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET) {
return false;
}
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 监听所有网络接口
serverAddr.sin_port = htons(port);
// 设置SO_REUSEADDR选项
int opt = 1;
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
if (bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cerr << "绑定端口失败: " << WSAGetLastError() << std::endl;
closesocket(serverSocket);
return false;
}
if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR) {
std::cerr << "监听失败: " << WSAGetLastError() << std::endl;
closesocket(serverSocket);
return false;
}
// 启动接收线程
acceptThread = std::thread([this]() {
while (true) {
sockaddr_in clientAddr;
int addrLen = sizeof(clientAddr);
SOCKET newClient = accept(serverSocket, (sockaddr*)&clientAddr, &addrLen);
if (newClient == INVALID_SOCKET) break;
std::lock_guard<std::mutex> lock(clientsMutex);
clients.push_back(newClient);
}
});
std::cout << "服务器已启动,监听端口: " << port << std::endl;
return true;
}
bool NetworkManager::connectToServer(const std::string& ip, int port) {
clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (clientSocket == INVALID_SOCKET) {
return false;
}
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
inet_pton(AF_INET, ip.c_str(), &serverAddr.sin_addr);
serverAddr.sin_port = htons(port);
if (connect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cerr << "连接服务器失败: " << WSAGetLastError() << std::endl;
closesocket(clientSocket);
return false;
}
std::cout << "已连接到服务器: " << ip << ":" << port << std::endl;
return true;
}
void NetworkManager::sendMessage(const std::string& message) {
// 服务器模式:广播给所有客户端
if (serverSocket != INVALID_SOCKET) {
std::lock_guard<std::mutex> lock(clientsMutex);
for (auto client : clients) {
send(client, message.c_str(), message.size(), 0);
}
}
// 客户端模式:发送到服务器
else if (clientSocket != INVALID_SOCKET) {
send(clientSocket, message.c_str(), message.size(), 0);
}
// 本地回显
if (messageCallback) {
messageCallback(message);
}
}
std::vector<std::string> NetworkManager::receiveMessages() {
std::vector<std::string> messages;
if (clientSocket == INVALID_SOCKET) {
return messages;
}
fd_set readSet;
FD_ZERO(&readSet);
FD_SET(clientSocket, &readSet);
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
if (select(clientSocket + 1, &readSet, nullptr, nullptr, &timeout) > 0) {
char buffer[1024];
int bytesReceived;
while ((bytesReceived = recv(clientSocket, buffer, sizeof(buffer), 0)) > 0) {
messages.emplace_back(buffer, bytesReceived);
}
}
return messages;
}
bool NetworkManager::isConnected() const {
return clientSocket != INVALID_SOCKET;
}

View File

@@ -0,0 +1,31 @@
#include "RoomInfo.hpp"
RoomInfo::RoomInfo(const std::string& name,
const std::string& ip,
int port,
const std::string& password)
: name(name), ipAddress(ip), port(port), password(password), userCount(0) {}
const std::string& RoomInfo::getName() const {
return name;
}
const std::string& RoomInfo::getIpAddress() const {
return ipAddress;
}
int RoomInfo::getPort() const {
return port;
}
const std::string& RoomInfo::getPassword() const {
return password;
}
int RoomInfo::getUserCount() const {
return userCount;
}
void RoomInfo::setUserCount(int count) {
userCount = count;
}

View File

@@ -0,0 +1,34 @@
#include "StringUtils.hpp"
#include <algorithm>
#include <cctype>
std::vector<std::string> StringUtils::split(const std::string& str, char delimiter) {
std::vector<std::string> tokens;
size_t start = 0;
size_t end = str.find(delimiter);
while (end != std::string::npos) {
tokens.push_back(str.substr(start, end - start));
start = end + 1;
end = str.find(delimiter, start);
}
tokens.push_back(str.substr(start));
return tokens;
}
std::string StringUtils::trim(const std::string& str) {
auto start = std::find_if_not(str.begin(), str.end(), [](int c) { return std::isspace(c); });
auto end = std::find_if_not(str.rbegin(), str.rend(), [](int c) { return std::isspace(c); }).base();
return (start >= end) ? "" : std::string(start, end);
}
bool StringUtils::startsWith(const std::string& str, const std::string& prefix) {
return str.size() >= prefix.size() &&
str.compare(0, prefix.size(), prefix) == 0;
}
bool StringUtils::endsWith(const std::string& str, const std::string& suffix) {
return str.size() >= suffix.size() &&
str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
}

View File

@@ -0,0 +1,25 @@
#include "User.hpp"
#include <chrono>
User::User(const std::string& username, const std::string& ip)
: username(username), ipAddress(ip) {
updateLastActive();
}
const std::string& User::getUsername() const {
return username;
}
const std::string& User::getIpAddress() const {
return ipAddress;
}
bool User::isActive() const {
auto now = std::chrono::system_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::minutes>(now - lastActive);
return duration.count() < 5; // 5分钟内活跃
}
void User::updateLastActive() {
lastActive = std::chrono::system_clock::now();
}

View File

@@ -0,0 +1,26 @@
#include "UserManager.hpp"
void UserManager::addUser(std::shared_ptr<User> user) {
users.push_back(user);
}
void UserManager::removeUser(const std::string& username) {
users.erase(
std::remove_if(users.begin(), users.end(),
[&username](const std::shared_ptr<User>& user) {
return user->getUsername() == username;
}),
users.end());
}
std::vector<std::shared_ptr<User>> UserManager::getUsers() const {
return users;
}
std::shared_ptr<User> UserManager::findUser(const std::string& username) const {
auto it = std::find_if(users.begin(), users.end(),
[&username](const std::shared_ptr<User>& user) {
return user->getUsername() == username;
});
return it != users.end() ? *it : nullptr;
}

View File

@@ -0,0 +1,6 @@
#include "Application.hpp"
int main(int argc, char** argv) {
Application app(argc, argv);
return app.run();
}