Created
March 25, 2026 12:03
-
-
Save Vitka999/fbe7ac20281f776390f58f5515ade49d to your computer and use it in GitHub Desktop.
Потужний чат
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <iostream> | |
| #include <string> | |
| #include <thread> | |
| #include <winsock2.h> | |
| #include <ws2tcpip.h> | |
| #include <windows.h> | |
| #pragma comment(lib, "ws2_32.lib") | |
| using namespace std; | |
| void setColor(int color) { | |
| SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color); | |
| } | |
| void setTitle(int count) { | |
| string title = "Users online: " + to_string(count); | |
| SetConsoleTitleA(title.c_str()); | |
| } | |
| void receiveMessages(SOCKET sock) { | |
| while (true) { | |
| char buffer[1024]{}; | |
| int len = recv(sock, buffer, sizeof(buffer), 0); | |
| if (len <= 0) break; | |
| string msg(buffer, len); | |
| if (msg.rfind("[COUNT]", 0) == 0) { | |
| int count = stoi(msg.substr(7)); | |
| setTitle(count); | |
| continue; | |
| } | |
| if (msg.rfind("[SERVER]", 0) == 0) { | |
| setColor(14); | |
| cout << msg; | |
| setColor(7); | |
| continue; | |
| } | |
| if (!msg.empty() && msg[0] == '[') { | |
| size_t end = msg.find(']'); | |
| int color = stoi(msg.substr(1, end - 1)); | |
| setColor(color); | |
| cout << msg.substr(end + 2); | |
| setColor(7); | |
| continue; | |
| } | |
| cout << msg; | |
| } | |
| } | |
| int main() { | |
| WSADATA wsaData; | |
| WSAStartup(MAKEWORD(2, 2), &wsaData); | |
| SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); | |
| sockaddr_in serverAddr{}; | |
| serverAddr.sin_family = AF_INET; | |
| serverAddr.sin_port = htons(54000); | |
| inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr); | |
| connect(sock, (sockaddr*)&serverAddr, sizeof(serverAddr)); | |
| string login, password; | |
| int color; | |
| cout << "Login: "; | |
| getline(cin, login); | |
| cout << "Password: "; | |
| getline(cin, password); | |
| cout << "Color (1-15): "; | |
| cin >> color; | |
| cin.ignore(); | |
| string auth = login + "|" + password + "|" + to_string(color); | |
| send(sock, auth.c_str(), auth.size(), 0); | |
| char buffer[1024]{}; | |
| int len = recv(sock, buffer, sizeof(buffer), 0); | |
| string response(buffer, len); | |
| if (response.find("NEW") == 0) { | |
| cout << "You are a NEW user\n"; | |
| } | |
| else if (response.find("OLD") == 0) { | |
| cout << "Welcome back!\n"; | |
| } | |
| cout << "--------------------------\n"; | |
| thread(receiveMessages, sock).detach(); | |
| while (true) { | |
| string msg; | |
| getline(cin, msg); | |
| if (msg == "/exit") break; | |
| msg += "\n"; | |
| send(sock, msg.c_str(), msg.size(), 0); | |
| } | |
| closesocket(sock); | |
| WSACleanup(); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <iostream> | |
| #include <vector> | |
| #include <string> | |
| #include <sstream> | |
| #include <thread> | |
| #include <mutex> | |
| #include <algorithm> | |
| #include <fstream> | |
| #include <ctime> | |
| #include <iomanip> | |
| #include <winsock2.h> | |
| #include <ws2tcpip.h> | |
| #pragma comment(lib, "ws2_32.lib") | |
| using namespace std; | |
| struct ClientInfo { | |
| string login; | |
| string password; | |
| SOCKET socket; | |
| int color; | |
| time_t connectTime; | |
| }; | |
| vector<ClientInfo> registeredUsers; | |
| vector<ClientInfo> onlineClients; | |
| vector<string> chatHistory; | |
| mutex mtx; | |
| // TIME | |
| string getCurrentTime() { | |
| time_t now = time(0); | |
| tm localTime; | |
| localtime_s(&localTime, &now); | |
| stringstream ss; | |
| ss << "[" | |
| << setw(2) << setfill('0') << localTime.tm_hour << ":" | |
| << setw(2) << setfill('0') << localTime.tm_min << ":" | |
| << setw(2) << setfill('0') << localTime.tm_sec | |
| << "]"; | |
| return ss.str(); | |
| } | |
| string formatDuration(int seconds) { | |
| int h = seconds / 3600; | |
| int m = (seconds % 3600) / 60; | |
| int s = seconds % 60; | |
| stringstream ss; | |
| ss << setw(2) << setfill('0') << h << ":" | |
| << setw(2) << setfill('0') << m << ":" | |
| << setw(2) << setfill('0') << s; | |
| return ss.str(); | |
| } | |
| // USERS | |
| void loadUsers() { | |
| ifstream file("users.txt"); | |
| if (!file.is_open()) return; | |
| string line; | |
| while (getline(file, line)) { | |
| stringstream ss(line); | |
| ClientInfo user; | |
| ss >> user.login >> user.password >> user.color; | |
| registeredUsers.push_back(user); | |
| } | |
| } | |
| void saveUser(const ClientInfo& user) { | |
| ofstream file("users.txt", ios::app); | |
| if (!file.is_open()) return; | |
| file << user.login << " " | |
| << user.password << " " | |
| << user.color << "\n"; | |
| } | |
| // BROADCAST | |
| void broadcast(const string& message, SOCKET sender = INVALID_SOCKET) { | |
| lock_guard<mutex> lock(mtx); | |
| chatHistory.push_back(message); | |
| for (auto& c : onlineClients) { | |
| if (c.socket != sender) { | |
| send(c.socket, message.c_str(), message.size(), 0); | |
| } | |
| } | |
| } | |
| // COUNT | |
| void sendOnlineCount() { | |
| string msg = "[COUNT]" + to_string(onlineClients.size()); | |
| for (auto& c : onlineClients) { | |
| send(c.socket, msg.c_str(), msg.size(), 0); | |
| } | |
| } | |
| // REMOVE | |
| void removeClient(SOCKET sock) { | |
| lock_guard<mutex> lock(mtx); | |
| onlineClients.erase( | |
| remove_if(onlineClients.begin(), onlineClients.end(), | |
| [sock](const ClientInfo& c) { | |
| return c.socket == sock; | |
| }), | |
| onlineClients.end() | |
| ); | |
| } | |
| // CLIENT | |
| void handleClient(SOCKET clientSocket) { | |
| char buffer[1024]{}; | |
| int bytes = recv(clientSocket, buffer, sizeof(buffer), 0); | |
| if (bytes <= 0) { | |
| closesocket(clientSocket); | |
| return; | |
| } | |
| string data(buffer, bytes); | |
| stringstream ss(data); | |
| string login, password, colorStr; | |
| getline(ss, login, '|'); | |
| getline(ss, password, '|'); | |
| getline(ss, colorStr, '|'); | |
| int color = stoi(colorStr); | |
| bool isNew = true; | |
| int userColor = color; | |
| { | |
| lock_guard<mutex> lock(mtx); | |
| for (auto& u : registeredUsers) { | |
| if (u.login == login) { | |
| if (u.password == password) { | |
| isNew = false; | |
| userColor = u.color; | |
| } | |
| else { | |
| string err = "WRONG_PASSWORD"; | |
| send(clientSocket, err.c_str(), err.size(), 0); | |
| closesocket(clientSocket); | |
| return; | |
| } | |
| } | |
| } | |
| if (isNew) { | |
| ClientInfo newUser{ login, password, INVALID_SOCKET, userColor }; | |
| registeredUsers.push_back(newUser); | |
| saveUser(newUser); | |
| } | |
| } | |
| ClientInfo client{ login, password, clientSocket, userColor }; | |
| client.connectTime = time(0); | |
| { | |
| lock_guard<mutex> lock(mtx); | |
| onlineClients.push_back(client); | |
| } | |
| // STATUS | |
| string status = isNew ? "NEW" : "OLD"; | |
| send(clientSocket, status.c_str(), status.size(), 0); | |
| if (!isNew) { | |
| string welcome = "Welcome back, " + login + "\n"; | |
| send(clientSocket, welcome.c_str(), welcome.size(), 0); | |
| } | |
| // SEND HISTORY | |
| { | |
| lock_guard<mutex> lock(mtx); | |
| for (auto& msg : chatHistory) { | |
| send(clientSocket, msg.c_str(), msg.size(), 0); | |
| } | |
| } | |
| // JOIN | |
| string joinMsg = "[SERVER] " + getCurrentTime() + " " + login + " joined\n"; | |
| broadcast(joinMsg, clientSocket); | |
| sendOnlineCount(); | |
| // CHAT LOOP | |
| while (true) { | |
| char msg[1024]{}; | |
| int len = recv(clientSocket, msg, sizeof(msg), 0); | |
| if (len <= 0) break; | |
| string message(msg, len); | |
| // INFO | |
| if (message == "info\n") { | |
| string result = "=== ONLINE TIME ===\n"; | |
| lock_guard<mutex> lock(mtx); | |
| time_t now = time(0); | |
| for (auto& c : onlineClients) { | |
| int duration = (int)difftime(now, c.connectTime); | |
| result += c.login + " - " + formatDuration(duration) + "\n"; | |
| } | |
| result += "===================\n"; | |
| send(clientSocket, result.c_str(), result.size(), 0); | |
| continue; | |
| } | |
| string finalMessage = "[" + to_string(userColor) + "] " | |
| + getCurrentTime() + " " + login + ": " + message; | |
| cout << finalMessage; | |
| broadcast(finalMessage, clientSocket); | |
| } | |
| removeClient(clientSocket); | |
| string leaveMsg = "[SERVER] " + getCurrentTime() + " " + login + " left\n"; | |
| broadcast(leaveMsg, clientSocket); | |
| sendOnlineCount(); | |
| closesocket(clientSocket); | |
| } | |
| // MAIN | |
| int main() { | |
| WSADATA wsaData; | |
| WSAStartup(MAKEWORD(2, 2), &wsaData); | |
| loadUsers(); | |
| SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0); | |
| sockaddr_in serverAddr{}; | |
| serverAddr.sin_family = AF_INET; | |
| serverAddr.sin_port = htons(54000); | |
| serverAddr.sin_addr.s_addr = INADDR_ANY; | |
| bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)); | |
| listen(serverSocket, SOMAXCONN); | |
| cout << "Server started...\n"; | |
| while (true) { | |
| SOCKET clientSocket = accept(serverSocket, nullptr, nullptr); | |
| thread(handleClient, clientSocket).detach(); | |
| } | |
| closesocket(serverSocket); | |
| WSACleanup(); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment