Данная программа представляет собой простой текстовый чат между клиентом и сервером. Программа состоит из двух файлов: клиентской и серверной части.
Клиентская часть программы (первый файл) работает следующим образом. Сначала она подключается к указанному серверу по IP-адресу и порту, который вводит пользователь. Затем она запускает отдельный поток, который слушает входящие сообщения от сервера и выводит их в консоль. После этого она ждет ввода пользователем сообщения и отправляет его на сервер. Клиент может завершить свою работу, отправив сообщение "/exit".
Серверная часть программы (второй файл) также начинается с подключения к порту и ожидания входящих подключений от клиентов. При подключении нового клиента сервер добавляет его в список клиентов и отправляет им сообщение о подключении нового участника чата. Затем сервер также запускает отдельный поток для каждого клиента, который слушает входящие сообщения от клиента и отправляет их всем остальным клиентам в чате. Когда клиент отключается от сервера, сервер удаляет его из списка клиентов и отправляет всем участникам сообщение об отключении клиента.
Код пользовательского клиента:
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <wininet.h>
#include <thread>
#include <string>
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "wininet.lib")
void receive_messages(SOCKET socket) {
char buffer[1024];
while (true) {
memset(buffer, 0, 1024); // Очистка буфера
int bytes_read = recv(socket, buffer, 1024, 0);
if (bytes_read <= 0) { // Если сервер отключился
std::cout << "Disconnected from server\n";
closesocket(socket);
exit(0);
}
std::cout << buffer << std::endl;
}
}
int main() {
WSADATA wsa_data;
if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) {
std::cerr << "Failed to initialize Winsock\n";
return 1;
}
std::cout << "List of current secure servers:\n";
HINTERNET hInternet = InternetOpenA("HTTP Example", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (hInternet == NULL)
{
std::cerr << "Failed to open internet connection" << std::endl;
return 1;
}
HINTERNET hUrl = InternetOpenUrlA(hInternet, "https://projectmp.ru/list.txt", NULL, 0, INTERNET_FLAG_RELOAD, 0);
if (hUrl == NULL)
{
std::cerr << "Failed to open URL" << std::endl;
InternetCloseHandle(hInternet);
return 1;
}
char buffer[1024];
DWORD bytesRead;
while (InternetReadFile(hUrl, buffer, sizeof(buffer), &bytesRead) && bytesRead != 0)
{
std::cout.write(buffer, bytesRead);
}
InternetCloseHandle(hUrl);
InternetCloseHandle(hInternet);
SOCKET client_socket = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket == -1) {
std::cerr << "Failed to create socket\n";
WSACleanup();
return 1;
}
std::string ip_address_str;
std::cout << "\n";
std::cout << "Enter server IP address: ";
std::getline(std::cin, ip_address_str);
sockaddr_in server_address;
server_address.sin_family = AF_INET;
const char* ip_address = ip_address_str.c_str();
wchar_t wide_ip_address[256];
MultiByteToWideChar(CP_ACP, 0, ip_address, -1, wide_ip_address, 256);
InetPton(AF_INET, wide_ip_address, &server_address.sin_addr.s_addr); // Адрес сервера
int port;
std::cout << "Enter server port number: ";
std::cin >> port;
server_address.sin_port = htons(port); // Порт сервера
if (connect(client_socket, (sockaddr*)&server_address, sizeof(server_address)) == SOCKET_ERROR) {
std::cerr << "Failed to connect to server\n";
closesocket(client_socket);
WSACleanup();
return 1;
}
std::cout << "Connected to server\n";
std::thread receive_thread(receive_messages, client_socket);
receive_thread.detach();
std::string message;
while (true) {
std::getline(std::cin, message);
if (message == "/exit") {
break;
}
send(client_socket, message.c_str(), message.size(), 0);
}
closesocket(client_socket);
WSACleanup();
return 0;
}
Код серверной части проекта
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <thread>
#include <vector>
#include <cstring>
#include <string>
#pragma comment(lib, "ws2_32.lib")
void handle_client(SOCKET client_socket, std::vector<SOCKET>& clients) {
char buffer[1024];
std::string connect_message = "User " + std::to_string(client_socket) + " has joined the chat\n";
for (SOCKET client : clients) {
send(client, connect_message.c_str(), connect_message.size(), 0);
}
while (true) {
memset(buffer, 0, 1024); // Очистка буфера
int bytes_read = recv(client_socket, buffer, 1024, 0);
if (bytes_read <= 0) { // Если клиент отключился
std::cout << "User " << client_socket << " has left the chat\n";
auto it = std::find(clients.begin(), clients.end(), client_socket);
if (it != clients.end()) {
clients.erase(it);
}
std::string disconnect_message = "User " + std::to_string(client_socket) + " has left the chat\n";
for (SOCKET client : clients) {
send(client, disconnect_message.c_str(), disconnect_message.size(), 0);
}
closesocket(client_socket);
break;
}
std::cout << "User " << client_socket << " sent a message: " << buffer << std::endl;
std::string message = std::to_string(client_socket) + ": " + buffer; // Формирование сообщения с префиксом id
for (SOCKET client : clients) { // Отправка сообщения всем клиентам
if (client != client_socket) {
send(client, message.c_str(), message.size(), 0);
}
}
}
}
int main(int argc, char* argv[]) {
int port;
std::cerr << "Enter server port: " << std::endl;
std::cin >> port;
if (argc > 1) {
port = std::stoi(argv[1]);
}
WSADATA wsa_data;
int result = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if (result != 0) {
std::cerr << "WSAStartup failed with error: " << result << std::endl;
return 1;
}
SOCKET server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server_socket == INVALID_SOCKET) {
std::cerr << "Failed to create socket: " << WSAGetLastError() << std::endl;
WSACleanup();
return 1;
}
sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = INADDR_ANY;
server_address.sin_port = htons(port);
if (bind(server_socket, (sockaddr*)&server_address, sizeof(server_address)) == SOCKET_ERROR) {
std::cerr << "Failed to bind socket to port: " << WSAGetLastError() << std::endl;
closesocket(server_socket);
WSACleanup();
return 1;
}
// Добавление кода для вывода внешнего ip и порта
char hostname[256];
result = gethostname(hostname, sizeof(hostname));
if (result != 0) {
std::cerr << "Failed to get hostname: " << WSAGetLastError() << std::endl;
WSACleanup();
return 1;
}
addrinfo* info;
result = getaddrinfo(hostname, NULL, NULL, &info);
if (result != 0) {
std::cerr << "Failed to get address info: " << result << std::endl;
WSACleanup();
return 1;
}
sockaddr_in* address = (sockaddr_in*)info->ai_addr;
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(address->sin_addr), ip, INET_ADDRSTRLEN);
std::cout << "IP address: " << ip << " Port: " << port << std::endl;
if (listen(server_socket, SOMAXCONN) == SOCKET_ERROR) {
std::cerr << "Failed to start listening on socket: " << WSAGetLastError() << std::endl;
closesocket(server_socket);
WSACleanup();
return 1;
}
std::vector<SOCKET> clients; // Вектор для хранения клиентских сокетов
while (true) {
sockaddr_in client_address;
int client_address_size = sizeof(client_address);
SOCKET client_socket = accept(server_socket, (sockaddr*)&client_address, &client_address_size);
if (client_socket == INVALID_SOCKET) {
std::cerr << "Failed to accept incoming connection: " << WSAGetLastError() << std::endl;
continue;
}
std::cout << "User " << client_socket << " has joined the chat\n";
clients.push_back(client_socket);
std::thread client_thread(handle_client, client_socket, std::ref(clients));
client_thread.detach();
}
closesocket(server_socket);
WSACleanup();
return 0;
}