Skip to content

Instantly share code, notes, and snippets.

@hmel1990
Last active April 28, 2025 13:55
Show Gist options
  • Save hmel1990/352a20a39c184a2206b7bf9895a08aad to your computer and use it in GitHub Desktop.
Save hmel1990/352a20a39c184a2206b7bf9895a08aad to your computer and use it in GitHub Desktop.
Homework chat cpp
==============================================================================================================================
SERVER
==============================================================================================================================
#include <winsock2.h>
#include <iostream>
#include <vector>
#include <string>
#include <ctime>
#include <windows.h>
#include <fstream>
using namespace std;
#define MAX_CLIENTS 10
#define DEFAULT_BUFLEN 4096
#pragma comment(lib, "ws2_32.lib") // Winsock library
#pragma warning(disable:4996)
SOCKET server_socket;
vector<string> history;
string filename = "history.txt";
static void saveHistory (const string& filename, vector <string>& history)
{
ofstream outfile(filename);
if (outfile.is_open())
{
for (const auto& message : history)
{
outfile << message << endl;
}
outfile.close();
}
}
int main() {
setlocale(0, "");
time_t now = time(0);
tm* ltm = localtime(&now);
char time_str[20];
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", ltm);
system("title Server");
puts("Start server... DONE.");
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
printf("Failed. Error Code: %d", WSAGetLastError());
return 1;
}
// create a socket
if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
printf("Could not create socket: %d", WSAGetLastError());
return 2;
}
// puts("Create socket... DONE.");
// prepare the sockaddr_in structure
sockaddr_in server;
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(1234);
// bind socket
if (bind(server_socket, (sockaddr*)&server, sizeof(server)) == SOCKET_ERROR) {
printf("Bind failed with error code: %d", WSAGetLastError());
return 3;
}
//puts("Bind socket... DONE.");
// listen to incoming connections
listen(server_socket, MAX_CLIENTS);
// accept and incoming connection
puts("Server is waiting for incoming connections...\nPlease, start one or more client-side app.");
// size of our receive buffer, this is string length
// set of socket descriptors
// fd means "file descriptors"
fd_set readfds; // https://docs.microsoft.com/en-us/windows/win32/api/winsock/ns-winsock-fd_set
SOCKET client_socket[MAX_CLIENTS] = {};
string client_names[MAX_CLIENTS];
while (true) {
// clear the socket fdset
FD_ZERO(&readfds);
// add master socket to fdset
FD_SET(server_socket, &readfds);
// add child sockets to fdset
for (int i = 0; i < MAX_CLIENTS; i++) {
SOCKET s = client_socket[i];
if (s > 0) {
FD_SET(s, &readfds);
}
}
// wait for an activity on any of the sockets, timeout is NULL, so wait indefinitely
if (select(0, &readfds, NULL, NULL, NULL) == SOCKET_ERROR) {
printf("select function call failed with error code : %d", WSAGetLastError());
return 4;
}
// if something happened on the master socket, then its an incoming connection
SOCKET new_socket; // new client 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 function error");
return 5;
}
for (int i = 0; i < history.size(); i++)
{
cout << history[i] << "\n";
send(new_socket, history[i].c_str(), history[i].size(), 0);
}
// inform server side of socket number - used in send and recv commands
printf("New connection, socket fd is %d, ip is: %s, port: %d\n", new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port));
// add new socket to array of sockets
for (int i = 0; i < MAX_CLIENTS; i++) {
if (client_socket[i] == 0) {
client_socket[i] = new_socket;
printf("Adding to list of sockets at index %d\n", i);
break;
}
}
}
// if some of client sockets sends something
for (int i = 0; i < MAX_CLIENTS; i++)
{
SOCKET s = client_socket[i];
// if client presend in read sockets
if (FD_ISSET(s, &readfds))
{
// get details of the client
getpeername(s, (sockaddr*)&address, (int*)&addrlen);
// check if it was for closing, and also read the incoming message
// recv does not place a null terminator at the end of the string (whilst printf %s assumes there is one)
char client_message[DEFAULT_BUFLEN];
int client_message_length = recv(s, client_message, DEFAULT_BUFLEN, 0);
client_message[client_message_length] = '\0';
if (client_names[i].empty()) {
client_names[i] = client_message; // первое сообщение — это ник !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
string welcome = "Ваш ник зарегистрирован как: " + client_names[i] + "\n";
send(s, welcome.c_str(), welcome.length(), 0);
continue;
}
string check_exit = client_message;
if (check_exit == "off")
{
cout << "Client #" << i << " is off\n";
client_socket[i] = 0;
}
string temp = client_message;
// temp += "\n";
history.push_back(temp);
string full_message = "[" + string(time_str) + "] [" + client_names[i] + "]: " + client_message; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
history.push_back(full_message);
for (int i = 0; i < MAX_CLIENTS; i++) {
if (client_socket[i] != 0) {
send(client_socket[i], full_message.c_str(), full_message.length(), 0); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
}
}
saveHistory(filename, history);
}
}
}
WSACleanup();
}
==============================================================================================================================
CLIENT
==============================================================================================================================
#define WIN32_LEAN_AND_MEAN
#include <ws2tcpip.h>
#include <windows.h>
#include <iostream>
#include <string>
using namespace std;
#pragma comment (lib, "Ws2_32.lib")
#define DEFAULT_BUFLEN 4096
#define SERVER_IP "127.0.0.1"
#define DEFAULT_PORT "1234"
SOCKET client_socket;
DWORD WINAPI Sender(void* param)
{
// під час запуску клієнта можна запросити його нік, колір повідомлень тощо
// string nick;
// cin >> nick;
while (true) {
// cout << "Please insert your query for server: ";
char query[DEFAULT_BUFLEN];
cin.getline(query, DEFAULT_BUFLEN);
send(client_socket, query, strlen(query), 0);
// альтернативний варіант введення даних стрiнгом
// string query;
// getline(cin, query);
// send(client_socket, query.c_str(), query.size(), 0);
}
}
DWORD WINAPI Receiver(void* param)
{
while (true) {
char response[DEFAULT_BUFLEN];
int result = recv(client_socket, response, DEFAULT_BUFLEN, 0);
response[result] = '\0';
// cout << "...\nYou have new response from server: " << response << "\n";
cout << response << "\n";
// cout << "Please insert your query for server: ";
}
}
BOOL ExitHandler(DWORD whatHappening)
{
switch (whatHappening)
{
case CTRL_C_EVENT: // closing console by ctrl + c
case CTRL_BREAK_EVENT: // ctrl + break
case CTRL_CLOSE_EVENT: // closing the console window by X button
case CTRL_LOGOFF_EVENT: // user logs off
case CTRL_SHUTDOWN_EVENT: // system is shutting down
cout << "Shutting down...\n";
Sleep(1000);
send(client_socket, "off", 3, 0);
return(TRUE);
break;
default:
return FALSE;
}
}
int main()
{
setlocale(0, "");
cout << "Вветиде свой ник...\n";
// обробник закриття вікна консолі
SetConsoleCtrlHandler((PHANDLER_ROUTINE)ExitHandler, true);
system("title Client");
// initialize Winsock
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
addrinfo hints = {};
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// resolve the server address and port
addrinfo* result = nullptr;
iResult = getaddrinfo(SERVER_IP, DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 2;
}
addrinfo* ptr = nullptr;
// attempt to connect to an address until one succeeds
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
// create a client-side socket for connecting to server
client_socket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (client_socket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 3;
}
// connect to server
iResult = connect(client_socket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(client_socket);
client_socket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (client_socket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 5;
}
CreateThread(0, 0, Sender, 0, 0, 0);
CreateThread(0, 0, Receiver, 0, 0, 0);
Sleep(INFINITE);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment