Files
iovi-network/SimpleClient.cpp
T
2026-06-17 21:11:25 +03:00

104 lines
4.6 KiB
C++

#include "SimpleClient.h"
#include <iostream>
#include <stdexcept>
// 1. THE CONSTRUCTOR (Birth)
// We initialize the socket to INVALID. We haven't bought a telephone yet.
SimpleClient::SimpleClient() : clientSocket(INVALID_SOCKET) {}
// 2. THE DESTRUCTOR (Cleanup)
// When the Client object is destroyed, we must hang up the phone.
SimpleClient::~SimpleClient() {
if (clientSocket != INVALID_SOCKET) {
CLOSE_SOCKET(clientSocket);
}
}
// 3. THE CONNECT METHOD (The Dialing Algorithm)
bool SimpleClient::connectTo(const std::string& ip, int port) {
// =========================================================================
// STEP 1: CREATE THE SOCKET (Buying the physical telephone)
// =========================================================================
// Just like the server, we need a physical socket to communicate.
// AF_INET = IPv4, SOCK_STREAM = Reliable TCP connection.
clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == INVALID_SOCKET) {
std::cerr << "❌ Failed to create client socket!\n";
return false;
}
// =========================================================================
// STEP 2: SETUP THE ADDRESS (Looking up the phone number)
// =========================================================================
// We need to tell the OS *who* we want to call.
sockaddr_in serverAddr{};
serverAddr.sin_family = AF_INET; // IPv4
serverAddr.sin_port = htons(port); // The port number (e.g., 8080)
// inet_pton = "Internet Presentation to Network"
// It converts the human-readable text "127.0.0.1" into the 32-bit binary
// number that the computer's network card actually understands.
if (inet_pton(AF_INET, ip.c_str(), &serverAddr.sin_addr) <= 0) {
std::cerr << "❌ Invalid IP address format!\n";
return false;
}
// =========================================================================
// STEP 3: CONNECT (Dialing the number and waiting for an answer)
// =========================================================================
// This function BLOCKS (pauses) the program here until the server picks up.
// If the server isn't running, or the port is wrong, this will fail.
if (connect(clientSocket, reinterpret_cast<sockaddr*>(&serverAddr), sizeof(serverAddr)) == SOCKET_ERROR) {
std::cerr << "❌ Failed to connect to server at " << ip << ":" << port << "\n";
return false; // We couldn't get through, so we return false.
}
// If we reach here, the connection is successful! The line is open.
return true;
}
// 4. THE TALK METHOD (The Conversation Algorithm)
void SimpleClient::talk(const std::string& message) const {
// Safety check: Don't try to talk if we aren't connected!
if (clientSocket == INVALID_SOCKET) {
std::cerr << "⚠️ Cannot talk: Not connected to a server.\n";
return;
}
std::cout << "📤 Sending: " << message;
// =========================================================================
// STEP 4: SEND (Speaking into the microphone)
// =========================================================================
// We push our text message out through the open connection.
// We cast the length to 'int' to satisfy Windows, and it's perfectly safe
// because our messages are small.
send(clientSocket, message.c_str(), static_cast<int>(message.length()), 0);
// =========================================================================
// STEP 5: RECV (Listening for the echo)
// =========================================================================
char buffer[1025]; // Our listening box (1024 data + 1 for '\0')
// We BLOCK (wait) here until the server sends data back to us.
// We read up to 1024 bytes, leaving 1 byte for the stop-sign.
auto bytesReceived = recv(clientSocket, buffer, sizeof(buffer) - 1, 0);
if (bytesReceived > 0) {
// Convert to safe size_t for array indexing
const auto len = static_cast<size_t>(bytesReceived);
// Add the invisible C-string stop-sign
buffer[len] = '\0';
std::cout << "📥 Server echoed back: " << buffer << "\n";
} else {
// If bytesReceived is 0, the server hung up on us politely.
// If < 0, the connection broke.
std::cerr << "⚠️ Server disconnected or error occurred while waiting for echo.\n";
}
}
// Note: We do NOT call CLOSE_SOCKET() here.
// We want to keep the line open so the user can call talk() multiple times!
// The destructor (~EchoClient) will handle the final hang-up.