Skip to content

Instantly share code, notes, and snippets.

@Vitka999
Created March 25, 2026 12:03
Show Gist options
  • Select an option

  • Save Vitka999/fbe7ac20281f776390f58f5515ade49d to your computer and use it in GitHub Desktop.

Select an option

Save Vitka999/fbe7ac20281f776390f58f5515ade49d to your computer and use it in GitHub Desktop.
Потужний чат
#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();
}
#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