cin导致刷屏的问题

在cin>><int/float>时 如果我们输入一个字符 就会导致刷屏的结果 这是因为非数字字符无法被cin接收而一直停留在缓冲区,导致下一次cin时直接从缓存读数 但字符无法读取结果导致无限循环 这被很多人认为成库的bug

解决方法:

1> 在cin>><int/float>后加cin.ignore();  cin.clear();

cin.ignore()方法cin.ignore(   5,   'c'   )   的是从输入流(cin)中提取字符,提取的字符被忽略(ignore),不被使用。每抛弃一个字符,它都要计数和比较字符:如果计数值达到5或者被抛弃的字符是'c',则cin.ignore()   函数执行终止;否则,它继续等待。  它的一个常用功能就是用来清除以回车结束的输入缓冲区的内容,消除上一次输入对下一次输入的影响。比如可以这么用:cin.ignore(   1024,   '/n'   );,通常把第一个参数设置得足够大,这样实际上总是只有第二个参数   '/n'   起作用,所以这一句就是把回车(包括回车)之前的所以字符从输入缓冲(流)中清除出去。

cin.clear用法如果输入发生错误发生,那么流状态既被标记为错误,你必须清除这些错误状态,以使你的程序能正确适当地继续运行。要清除错误状态,需使用clear()函数。此函数带一个参数,它是你将要设为当前状态的标志值。,只要将ios::goodbit作为实参。

2> 在cin>><int/float>后加fflush(stdin);(需要stdio.h)

     注: fflush(stdin)刷新标准输入缓冲区,需要stdio.h
 

 

 

我抽象了一个小模型,代码如下

#include"iostream"

using namespace std;

int main()
{
 int n;
 cout<<"input:";
 cin>>n;
 while (n<=0)
 {
    cout<<"error,input agian!"<<endl;
    cin>>n;
  }

return 0;

}

看似毫无问题

调试时也往往被忽略

如输入一个正整数没问题

若输入非正整数也没问题

可当输入一个字母或其它时,将出现死循环

解决方法如下

#include"iostream"

using namespace std;

int main()
{
 int n;
 cout<<"input:";
 cin>>n;
 while (n<=0)
 {

    cin.clear();     ///

    cin.ignore();  ///


    cout<<"error,input agian!"<<endl;
    cin>>n;
  }

return 0;

}

cin.clear();前面状态为假了,再输入就不被执行了,清空缓冲区,并将错误的cin流标识,通过这个可以把假状态清除掉,加上cin.ignore()就可解决编译器编译while循环时因在缓冲区找不到合乎条件的数据而出现死循环的情况了。


 

#include <iostream> #include <winsock2.h> #include <ws2tcpip.h> #include <process.h> #include <vector> #include <string> #include <sstream> #include <mutex> #include <deque> #include <chrono> #include <algorithm> #pragma comment(lib, "ws2_32.lib") struct ClientInfo { SOCKET socket; std::string ip; std::string nickname; std::deque<std::chrono::steady_clock::time_point> messageTimes; // 防刷屏 int sensitiveWordCount = 0; // 敏感词计数 }; std::vector<ClientInfo> clients; std::mutex clientsMutex; // 敏感词列表 const std::vector<std::string> SENSITIVE_WORDS = {"78", "91", "蛋", "1241"}; // 替换字符串中的子串 std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) { size_t start_pos = 0; while ((start_pos = str.find(from, start_pos)) != std::string::npos) { str.replace(start_pos, from.length(), to); start_pos += to.length(); } return str; } // 敏感词过滤函数 std::string FilterSensitiveWords(const std::string& msg) { std::string result = msg; for (const auto& word : SENSITIVE_WORDS) { result = ReplaceAll(result, word, "***"); } return result; } // 检查是否刷屏 bool CheckFlooding(ClientInfo& client) { auto now = std::chrono::steady_clock::now(); client.messageTimes.push_back(now); // 保留最近5秒的消息时间 while (!client.messageTimes.empty() && now - client.messageTimes.front() > std::chrono::seconds(5)) { client.messageTimes.pop_front(); } // 如果最近2秒内发送超过5条消息,视为刷屏 if (client.messageTimes.size() >= 5 && now - client.messageTimes[client.messageTimes.size() - 5] < std::chrono::seconds(2)) { return true; } return false; } // 广播消息给所有客户端(可指定排除的 socket) 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); } } } // 向指定 socket 发送消息 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 (auto it = clients.begin(); it != clients.end(); ++it) { if (it->nickname == nickname) { std::string kickMsg = "[系统] 你已被管理员踢出聊天室"; std::string broadcastMsg = "[系统] 用户 " + nickname + " 被踢出聊天室"; std::cout << broadcastMsg << std::endl; SendToOne(it->socket, kickMsg); BroadcastMessage(broadcastMsg, it->socket); closesocket(it->socket); clients.erase(it); return; } } std::cout << "未找到昵称为 " << nickname << " 的用户。" << std::endl; } // 客户端处理线程 unsigned __stdcall ClientThread(void* lpParam) { SOCKET clientSocket = (SOCKET)lpParam; char buffer[1024]; int bytesReceived; // 接收昵称 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); // 获取IP地址 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; { 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); std::string filteredMsg = FilterSensitiveWords(rawMsg); // 查找当前用户信息 ClientInfo* currentUser = nullptr; { std::lock_guard<std::mutex> lock(clientsMutex); for (auto& client : clients) { if (client.socket == clientSocket) { currentUser = &client; break; } } } if (!currentUser) { break; } // 防刷屏检测 if (CheckFlooding(*currentUser)) { std::string kickMsg = "[系统] 你因刷屏被踢出聊天室"; std::string broadcastMsg = "[系统] 用户 " + currentUser->nickname + " 因刷屏被踢出聊天室"; std::cout << broadcastMsg << std::endl; SendToOne(currentUser->socket, kickMsg); 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) { std::string kickMsg = "[系统] 你因连续发送敏感词被踢出聊天室"; std::string broadcastMsg = "[系统] 用户 " + currentUser->nickname + " 因连续发送敏感词被踢出聊天室"; std::cout << broadcastMsg << std::endl; SendToOne(currentUser->socket, kickMsg); BroadcastMessage(broadcastMsg, currentUser->socket); KickUser(currentUser->nickname); break; } continue; // 不广播该消息 } // 正常广播消息 std::string clientMsg = "[" + currentUser->nickname + "] : " + filteredMsg; 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 (auto it = clients.begin(); it != clients.end(); ++it) { if (it->socket == clientSocket) { clients.erase(it); 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; } 修改这份代码,你自己找Bug,自行修改
09-07
#include <iostream> #include <winsock2.h> #include <ws2tcpip.h> #include <process.h> #include <string> #include <windows.h> // 用于 Sleep() 和颜色控制 #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), 0)) > 0) { buffer[bytesReceived] = '\0'; std::string msg(buffer); if (msg.find("被踢出聊天室") != std::string::npos) { SetColor(12); // 红色 std::cout << "【服务器断开连接】" << std::endl; Sleep(1000); 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; 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); SetColor(15); // 默认白色 std::string message; while (true) { SetColor(15); // 淡蓝色 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; } 还是有Bug(提示:踢完人之后所有人同时掉线,/kick , 刷屏踢人 , 敏感词踢人都是)
09-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值