initial
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
#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.
|
||||
Reference in New Issue
Block a user