C++中cin刷屏问题

单纯使用cin输入字符串,会忽略掉’\n’,因此接着再使用cin时,会读到’\n’,为了消除回车的影响,可以使用,cin.ignore(int,char)。作用就是,从输入流 cin 中提取字符被忽略,不被使用。而每抛弃一个字符,它都要进行计数和比较字符:如果计数值达到 int 或者被抛弃的字符是 char ,则cin.ignore() 函数执行终止;否则,它继续等待。

下面是你要求的优化后的服务器端和客户端代码,其中客户端代码基于 **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; } ``` --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值