Skip to content

Instantly share code, notes, and snippets.

@m1irka
Created April 2, 2026 08:25
Show Gist options
  • Select an option

  • Save m1irka/3c07106584dca77745f370ffdb3490b2 to your computer and use it in GitHub Desktop.

Select an option

Save m1irka/3c07106584dca77745f370ffdb3490b2 to your computer and use it in GitHub Desktop.
чат TCP
#include <ws2tcpip.h>
#include <windows.h>
#include <iostream>
#include <string>
#include <vector>
#include <chrono>
using namespace std;
using namespace std::chrono;
#pragma comment (lib, "Ws2_32.lib")
#define DEFAULT_BUFLEN 4096
#define SERVER_IP "127.0.0.1"
#define DEFAULT_PORT "8888"
SOCKET client_socket;
string login;
int userColor = 7;
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
auto lastMessageTime = steady_clock::now();
vector<string> bannedWords = { "C++", "badword1", "badword2" };
DWORD WINAPI Sender(void* param) {
while (true) {
string query;
getline(cin, query);
auto now = steady_clock::now();
auto diff = duration_cast<seconds>(now - lastMessageTime).count();
if (diff < 1) {
cout << "Anti-flood: you cannot send more than one message per second.\n";
continue;
}
lastMessageTime = now;
for (auto& word : bannedWords) {
size_t pos;
while ((pos = query.find(word)) != string::npos) {
query.replace(pos, word.size(), "%$#@#%$#@");
}
}
if (query.empty()) continue;
string message = login + ":" + query + ":" + to_string(userColor);
send(client_socket, message.c_str(), static_cast<int>(message.size()), 0);
}
}
DWORD WINAPI Receiver(void* param) {
while (true) {
char response[DEFAULT_BUFLEN];
int result = recv(client_socket, response, DEFAULT_BUFLEN, 0);
if (result <= 0) continue;
if (result >= DEFAULT_BUFLEN) response[DEFAULT_BUFLEN - 1] = '\0';
else response[result] = '\0';
string received = response;
// Проверка на CLIENT_COUNT
if (received.find("CLIENT_COUNT:") == 0) {
int count = stoi(received.substr(13));
string title = "Client - Users online: " + to_string(count);
SetConsoleTitleA(title.c_str()); // ANSI версия
continue;
}
size_t pos1 = received.find(":");
size_t pos2 = received.find(":", pos1 + 1);
if (pos1 == string::npos || pos2 == string::npos) {
cout << received << "\n";
continue;
}
string sender = received.substr(0, pos1);
string text = received.substr(pos1 + 1, pos2 - pos1 - 1);
int color = stoi(received.substr(pos2 + 1));
SetConsoleTextAttribute(hConsole, color);
cout << sender << ": " << text << "\n";
SetConsoleTextAttribute(hConsole, 7);
}
}
BOOL ExitHandler(DWORD whatHappening) {
switch (whatHappening) {
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
cout << "Shutting down...\n";
Sleep(1000);
send(client_socket, "off", 3, 0);
return TRUE;
default:
return FALSE;
}
}
int main() {
SetConsoleCtrlHandler((PHANDLER_ROUTINE)ExitHandler, true);
system("title Client");
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
cout << "WSAStartup failed with error: " << iResult << "\n";
return 1;
}
addrinfo hints{};
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
addrinfo* result = nullptr;
iResult = getaddrinfo(SERVER_IP, DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
cout << "getaddrinfo failed with error: " << iResult << "\n";
WSACleanup();
return 2;
}
addrinfo* ptr = nullptr;
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
client_socket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (client_socket == INVALID_SOCKET) {
cout << "Socket creation failed: " << WSAGetLastError() << "\n";
WSACleanup();
return 3;
}
iResult = connect(client_socket, ptr->ai_addr, static_cast<int>(ptr->ai_addrlen));
if (iResult == SOCKET_ERROR) {
closesocket(client_socket);
client_socket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (client_socket == INVALID_SOCKET) {
cout << "Unable to connect to server!\n";
WSACleanup();
return 5;
}
string password;
cout << "Enter login: ";
getline(cin, login);
cout << "Enter password: ";
getline(cin, password);
cout << "Choose your message color (1-15): ";
cin >> userColor;
cin.ignore();
string credentials = login + ":" + password + ":" + to_string(userColor);
send(client_socket, credentials.c_str(), static_cast<int>(credentials.size()), 0);
system("cls");
cout << "Welcome to the chat, " << login << "!\n";
CreateThread(0, 0, Sender, 0, 0, 0);
CreateThread(0, 0, Receiver, 0, 0, 0);
Sleep(INFINITE);
}
#include <winsock2.h>
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <chrono>
using namespace std;
using namespace std::chrono;
#define MAX_CLIENTS 20
#define DEFAULT_BUFLEN 4096
#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable:4996)
SOCKET server_socket;
struct ClientInfo {
string login;
string password;
string ip;
int port = 0;
int color = 7;
steady_clock::time_point lastMessageTime;
steady_clock::time_point connectTime;
};
vector<ClientInfo> clients;
vector<string> history;
vector<string> bannedWords = { "C++", "badword1", "badword2" };
void loadClientsFromFile() {
ifstream fin("clients.txt");
if (!fin.is_open()) return;
ClientInfo info;
while (fin >> info.login >> info.password >> info.ip >> info.port >> info.color) {
info.lastMessageTime = steady_clock::now() - seconds(2);
info.connectTime = steady_clock::now();
clients.push_back(info);
}
fin.close();
}
void saveClientToFile(const ClientInfo& info) {
ofstream fout("clients.txt", ios::app);
fout << info.login << " " << info.password << " " << info.ip << " " << info.port << " " << info.color << "\n";
fout.close();
}
void broadcastClientCount(SOCKET client_socket[MAX_CLIENTS]) {
string count_msg = "CLIENT_COUNT:" + to_string(clients.size());
for (int j = 0; j < MAX_CLIENTS; j++) {
if (client_socket[j] != 0) {
send(client_socket[j], count_msg.c_str(), static_cast<int>(count_msg.size()), 0);
}
}
}
int main() {
system("title Server");
cout << "Server starting... done.\n";
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
cout << "WSAStartup failed. Error code: " << WSAGetLastError() << "\n";
return 1;
}
if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
cout << "Could not create socket. Error code: " << WSAGetLastError() << "\n";
return 2;
}
cout << "Server socket created.\n";
sockaddr_in server{};
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(8888);
if (bind(server_socket, (sockaddr*)&server, sizeof(server)) == SOCKET_ERROR) {
cout << "Bind failed. Error code: " << WSAGetLastError() << "\n";
return 3;
}
cout << "Bind successful.\n";
listen(server_socket, MAX_CLIENTS);
cout << "Waiting for incoming connections...\n";
fd_set readfds;
SOCKET client_socket[MAX_CLIENTS]{};
loadClientsFromFile();
while (true) {
FD_ZERO(&readfds);
FD_SET(server_socket, &readfds);
for (int i = 0; i < MAX_CLIENTS; i++) {
SOCKET s = client_socket[i];
if (s > 0) FD_SET(s, &readfds);
}
if (select(0, &readfds, NULL, NULL, NULL) == SOCKET_ERROR) {
cout << "Select failed. Error code: " << WSAGetLastError() << "\n";
return 4;
}
SOCKET new_socket;
sockaddr_in address;
int addrlen = sizeof(sockaddr_in);
if (FD_ISSET(server_socket, &readfds)) {
if ((new_socket = accept(server_socket, (sockaddr*)&address, &addrlen)) < 0) {
perror("Accept failed");
return 5;
}
char buffer[DEFAULT_BUFLEN];
int len = recv(new_socket, buffer, DEFAULT_BUFLEN, 0);
if (len > 0) {
if (len >= DEFAULT_BUFLEN) buffer[DEFAULT_BUFLEN - 1] = '\0';
else buffer[len] = '\0';
}
string credentials = buffer;
size_t pos1 = credentials.find(":");
size_t pos2 = credentials.find(":", pos1 + 1);
string login = credentials.substr(0, pos1);
string password = credentials.substr(pos1 + 1, pos2 - pos1 - 1);
int color = stoi(credentials.substr(pos2 + 1));
ClientInfo info{ login, password, inet_ntoa(address.sin_addr), ntohs(address.sin_port), color,
steady_clock::now() - seconds(2), steady_clock::now() };
bool knownClient = false;
for (auto& c : clients) {
if (c.login == login && c.password == password) {
knownClient = true;
break;
}
}
clients.push_back(info);
if (!knownClient) {
saveClientToFile(info);
cout << "New user: " << login << " (" << info.ip << ":" << info.port << ")\n";
}
else {
string welcomeBack = "Server:Welcome back, " + login + "!:" + to_string(info.color);
send(new_socket, welcomeBack.c_str(), static_cast<int>(welcomeBack.size()), 0);
}
string notification = "Server:" + login + " joined the chat:7";
history.push_back(notification);
for (int i = 0; i < MAX_CLIENTS; i++)
if (client_socket[i] != 0)
send(client_socket[i], notification.c_str(), static_cast<int>(notification.size()), 0);
for (int i = 0; i < MAX_CLIENTS; i++) {
if (client_socket[i] == 0) {
client_socket[i] = new_socket;
cout << "Added to socket list at index " << i << "\n";
break;
}
}
broadcastClientCount(client_socket);
}
for (int i = 0; i < MAX_CLIENTS; i++) {
SOCKET s = client_socket[i];
if (FD_ISSET(s, &readfds)) {
char client_message[DEFAULT_BUFLEN];
int client_message_length = recv(s, client_message, DEFAULT_BUFLEN, 0);
if (client_message_length > 0) {
if (client_message_length >= DEFAULT_BUFLEN) client_message[DEFAULT_BUFLEN - 1] = '\0';
else client_message[client_message_length] = '\0';
string check_exit = client_message;
if (check_exit == "off") {
cout << "Client #" << i << " disconnected\n";
client_socket[i] = 0;
string notification = "Server:Client #" + to_string(i) + " disconnected:7";
history.push_back(notification);
for (int j = 0; j < MAX_CLIENTS; j++)
if (client_socket[j] != 0)
send(client_socket[j], notification.c_str(), static_cast<int>(notification.size()), 0);
broadcastClientCount(client_socket);
}
else {
string msg = client_message;
size_t pos1 = msg.find(":");
size_t pos2 = msg.find(":", pos1 + 1);
string sender = msg.substr(0, pos1);
string text = msg.substr(pos1 + 1, pos2 - pos1 - 1);
if (text == "info") {
cout << "----------------- Clients info -----------------\n";
for (auto& c : clients) {
auto now = steady_clock::now();
auto diff = duration_cast<seconds>(now - c.connectTime).count();
int h = static_cast<int>(diff / 3600);
int m = static_cast<int>((diff % 3600) / 60);
int s = static_cast<int>(diff % 60);
cout << c.login
<< " (" << c.ip << ":" << c.port << ") "
<< "Color=" << c.color
<< " Time online: " << h << ":" << m << ":" << s << "\n";
}
cout << "------------------\n";
}
else {
for (auto& word : bannedWords) {
size_t pos;
while ((pos = msg.find(word)) != string::npos) {
msg.replace(pos, word.size(), "%$#@#%$#@");
}
}
}
for (auto& c : clients) {
if (msg.find(c.login + ":") == 0) {
auto now = steady_clock::now();
auto diff = duration_cast<seconds>(now - c.lastMessageTime).count();
if (diff < 1) {
cout << "Anti-flood: message from " << c.login << " blocked.\n";
msg.clear();
}
else {
c.lastMessageTime = now;
}
break;
}
}
if (!msg.empty()) {
history.push_back(msg);
for (int j = 0; j < MAX_CLIENTS; j++) {
if (client_socket[j] != 0 && client_socket[j] != s) {
send(client_socket[j], msg.c_str(), static_cast<int>(msg.size()), 0);
}
}
}
broadcastClientCount(client_socket);
}
}
}
}
}
WSACleanup();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment