Last active
April 28, 2025 13:55
-
-
Save hmel1990/352a20a39c184a2206b7bf9895a08aad to your computer and use it in GitHub Desktop.
Homework chat cpp
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
============================================================================================================================== | |
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