下面是你要求的优化后的服务器端和客户端代码,其中客户端代码基于 **C++98 标准**,不使用任何 C++11 特性(如 `auto`、`nullptr`、`std::shared_ptr`、`std::atomic` 等),并修复了踢人功能、线程安全、连接管理等问题。
---
### ✅ 优化后的服务器端代码(C++11/14)
```cpp
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <process.h>
#include <vector>
#include <string>
#include <sstream>
#include <windows.h>
#include <mutex>
#include <deque>
#include <ctime>
#include <algorithm>
#include <regex>
#pragma comment(lib, "ws2_32.lib")
struct ClientInfo {
SOCKET socket;
std::string ip;
std::string nickname;
std::deque<time_t> messageTimes;
int sensitiveWordCount;
};
std::vector<ClientInfo> clients;
std::mutex clientsMutex;
const std::vector<std::string> SENSITIVE_WORDS = {"78", "91", "蛋", "1241"};
const std::string KICK_MESSAGE = "__KICKED__";
const std::string HEARTBEAT_MSG = "__HEARTBEAT__";
std::string FilterSensitiveWords(const std::string& msg) {
std::string result = msg;
for (const auto& word : SENSITIVE_WORDS) {
result = std::regex_replace(result, std::regex(word), "***");
}
return result;
}
bool CheckFlooding(ClientInfo& client) {
time_t now = time(0);
client.messageTimes.push_back(now);
while (!client.messageTimes.empty() && now - client.messageTimes.front() > 5) {
client.messageTimes.pop_front();
}
if (client.messageTimes.size() >= 5) {
return true;
}
return false;
}
void BroadcastMessage(const std::string& msg, SOCKET sender = INVALID_SOCKET) {
std::lock_guard<std::mutex> lock(clientsMutex);
for (const auto& client : clients) {
if (client.socket != sender) {
send(client.socket, msg.c_str(), static_cast<int>(msg.size()), 0);
}
}
}
void SendToOne(SOCKET sock, const std::string& msg) {
send(sock, msg.c_str(), static_cast<int>(msg.size()), 0);
}
void KickUser(const std::string& nickname) {
std::lock_guard<std::mutex> lock(clientsMutex);
for (size_t i = 0; i < clients.size(); ++i) {
if (clients[i].nickname == nickname) {
std::string kickMsg = KICK_MESSAGE;
std::string broadcastMsg = "[系统] 用户 " + nickname + " 被踢出聊天室";
std::cout << broadcastMsg << std::endl;
send(clients[i].socket, kickMsg.c_str(), kickMsg.size(), 0);
BroadcastMessage(broadcastMsg, clients[i].socket);
closesocket(clients[i].socket);
clients.erase(clients.begin() + i);
return;
}
}
std::cout << "未找到昵称为 " << nickname << " 的用户。" << std::endl;
}
bool IsNicknameExists(const std::string& nickname) {
std::lock_guard<std::mutex> lock(clientsMutex);
for (const auto& client : clients) {
if (client.nickname == nickname) {
return true;
}
}
return false;
}
unsigned __stdcall ClientThread(void* lpParam) {
SOCKET clientSocket = (SOCKET)lpParam;
char buffer[1024];
int bytesReceived;
int timeout = 10000;
setsockopt(clientSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
bytesReceived = recv(clientSocket, buffer, sizeof(buffer) - 1, 0);
if (bytesReceived <= 0) {
std::cerr << "接收昵称失败。" << std::endl;
closesocket(clientSocket);
return 0;
}
buffer[bytesReceived] = '\0';
std::string nickname(buffer);
if (IsNicknameExists(nickname)) {
std::string rejectMsg = "[系统] 昵称已被占用,请重新连接并设置新昵称";
SendToOne(clientSocket, rejectMsg);
closesocket(clientSocket);
return 0;
}
sockaddr_in clientAddr;
int addrLen = sizeof(clientAddr);
getpeername(clientSocket, (sockaddr*)&clientAddr, &addrLen);
std::string ip(inet_ntoa(clientAddr.sin_addr));
ClientInfo info;
info.socket = clientSocket;
info.ip = ip;
info.nickname = nickname;
info.sensitiveWordCount = 0;
{
std::lock_guard<std::mutex> lock(clientsMutex);
clients.push_back(info);
}
std::string joinMsg = "[系统] " + info.nickname + " 加入了聊天室";
std::string fullJoinMsg = "[系统][" + info.ip + "][" + info.nickname + "] 加入了聊天室";
std::cout << fullJoinMsg << std::endl;
BroadcastMessage(joinMsg);
while (true) {
bytesReceived = recv(clientSocket, buffer, sizeof(buffer) - 1, 0);
if (bytesReceived <= 0) break;
buffer[bytesReceived] = '\0';
std::string rawMsg(buffer);
if (rawMsg == KICK_MESSAGE || rawMsg == HEARTBEAT_MSG) continue;
ClientInfo* currentUser = NULL;
{
std::lock_guard<std::mutex> lock(clientsMutex);
for (size_t i = 0; i < clients.size(); ++i) {
if (clients[i].socket == clientSocket) {
currentUser = &clients[i];
break;
}
}
}
if (!currentUser) break;
if (CheckFlooding(*currentUser)) {
SendToOne(currentUser->socket, KICK_MESSAGE);
std::string broadcastMsg = "[系统] 用户 " + currentUser->nickname + " 因刷屏被踢出聊天室";
std::cout << broadcastMsg << std::endl;
BroadcastMessage(broadcastMsg, currentUser->socket);
KickUser(currentUser->nickname);
break;
}
bool containsSensitiveWord = false;
for (const auto& word : SENSITIVE_WORDS) {
if (rawMsg.find(word) != std::string::npos) {
containsSensitiveWord = true;
break;
}
}
if (containsSensitiveWord) {
currentUser->sensitiveWordCount++;
std::string warnMsg = "[系统] 用户 " + currentUser->nickname + " 发送敏感词,已警告 " + std::to_string(currentUser->sensitiveWordCount) + " 次";
std::cout << warnMsg << std::endl;
BroadcastMessage(warnMsg);
if (currentUser->sensitiveWordCount >= 3) {
SendToOne(currentUser->socket, KICK_MESSAGE);
std::string broadcastMsg = "[系统] 用户 " + currentUser->nickname + " 因连续发送敏感词被踢出聊天室";
std::cout << broadcastMsg << std::endl;
BroadcastMessage(broadcastMsg, currentUser->socket);
KickUser(currentUser->nickname);
break;
}
continue;
}
std::string clientMsg = "[" + currentUser->nickname + "] : " + FilterSensitiveWords(rawMsg);
std::string serverMsg = "[" + currentUser->ip + "][" + currentUser->nickname + "] : " + rawMsg;
std::cout << serverMsg << std::endl;
BroadcastMessage(clientMsg, clientSocket);
}
std::string leaveMsg = "[系统] " + nickname + " 离开了聊天室";
std::cout << leaveMsg << std::endl;
BroadcastMessage(leaveMsg);
{
std::lock_guard<std::mutex> lock(clientsMutex);
for (size_t i = 0; i < clients.size(); ++i) {
if (clients[i].socket == clientSocket) {
clients.erase(clients.begin() + i);
break;
}
}
}
closesocket(clientSocket);
return 0;
}
unsigned __stdcall ServerInputThread(void* lpParam) {
while (true) {
std::string input;
std::getline(std::cin, input);
if (input == "/list") {
std::lock_guard<std::mutex> lock(clientsMutex);
std::cout << "当前在线用户:" << std::endl;
for (const auto& client : clients) {
std::cout << "[" << client.ip << "] " << client.nickname << std::endl;
}
} else if (input.substr(0, 6) == "/kick ") {
if (input.size() > 6) {
KickUser(input.substr(6));
} else {
std::cout << "请输入要踢出的用户昵称。" << std::endl;
}
} else if (!input.empty()) {
std::string msg = "[管理员] : " + input;
std::cout << msg << std::endl;
BroadcastMessage(msg);
}
}
return 0;
}
int main() {
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "WSAStartup 失败。" << std::endl;
return 1;
}
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET) {
std::cerr << "创建 socket 失败。" << std::endl;
WSACleanup();
return 1;
}
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(12345);
serverAddr.sin_addr.s_addr = INADDR_ANY;
if (bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cerr << "绑定失败。" << std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR) {
std::cerr << "监听失败。" << std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
std::cout << "【聊天室服务器已启动】" << std::endl;
std::cout << "请输入命令:" << std::endl;
std::cout << " /list 查看在线用户" << std::endl;
std::cout << " /kick 昵称 踢出用户" << std::endl;
_beginthreadex(nullptr, 0, ServerInputThread, nullptr, 0, nullptr);
while (true) {
SOCKET clientSocket = accept(serverSocket, nullptr, nullptr);
if (clientSocket != INVALID_SOCKET) {
_beginthreadex(nullptr, 0, ClientThread, (void*)clientSocket, 0, nullptr);
}
}
closesocket(serverSocket);
WSACleanup();
return 0;
}
```
---
### ✅ 优化后的客户端代码(C++98)
```cpp
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <process.h>
#include <string>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
SOCKET clientSocket;
std::string myNickname;
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
void SetColor(int color) {
SetConsoleTextAttribute(hConsole, color);
}
unsigned __stdcall ReceiveThread(void* lpParam) {
char buffer[1024];
int bytesReceived;
while ((bytesReceived = recv(clientSocket, buffer, sizeof(buffer) - 1, 0)) > 0) {
buffer[bytesReceived] = '\0';
std::string msg(buffer);
if (msg == "__KICKED__") {
SetColor(12);
std::cout << "【你已被踢出聊天室】" << std::endl;
Sleep(2000);
exit(0);
}
std::string prefix = myNickname + " : ";
if (msg.find(prefix) == 0) {
continue;
}
if (msg.find("[系统]") == 0) {
SetColor(10);
} else if (msg.find("[管理员]") == 0) {
SetColor(13);
} else if (msg.find("]") != std::string::npos && msg[0] == '[') {
SetColor(15);
} else {
SetColor(7);
}
std::cout << msg << std::endl;
SetColor(15);
}
SetColor(12);
std::cout << "【服务器已断开连接】" << std::endl;
Sleep(2000);
exit(0);
return 0;
}
unsigned __stdcall HeartbeatThread(void* lpParam) {
while (true) {
std::string heartbeat = "__HEARTBEAT__";
int sent = send(clientSocket, heartbeat.c_str(), heartbeat.size(), 0);
if (sent == SOCKET_ERROR) {
std::cerr << "【断开链接】" << std::endl;
exit(0);
}
Sleep(3000);
}
return 0;
}
int main() {
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetColor(11);
std::cout << "========================================" << std::endl;
std::cout << " 欢迎来到网络聊天室 " << std::endl;
std::cout << "========================================" << std::endl;
clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(12345);
serverAddr.sin_addr.s_addr = inet_addr("192.168.8.41");
if (connect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
SetColor(12);
std::cerr << "【连接失败】" << std::endl;
return 1;
}
std::string nickname;
SetColor(14);
std::cout << "请输入你的昵称:";
std::getline(std::cin, nickname);
myNickname = nickname;
send(clientSocket, nickname.c_str(), nickname.size(), 0);
system("cls");
SetColor(10);
std::cout << "【欢迎来到聊天室," << nickname << "!】" << std::endl;
std::cout << "【输入 /exit 退出聊天室】" << std::endl;
std::cout << "----------------------------------------" << std::endl;
SetColor(15);
_beginthreadex(0, 0, ReceiveThread, 0, 0, 0);
_beginthreadex(0, 0, HeartbeatThread, 0, 0, 0);
SetColor(15);
std::string message;
while (true) {
SetColor(9);
std::getline(std::cin, message);
if (message == "/exit") {
closesocket(clientSocket);
WSACleanup();
return 0;
}
SetColor(15);
send(clientSocket, message.c_str(), message.size(), 0);
}
closesocket(clientSocket);
WSACleanup();
return 0;
}
```
---
###