ππ» μ΄μ μ½λμμ κ°λ
μ±μ μν΄μ νμΌμ λΆλ¦¬νμ΅λλ€.
I separated the files in the previous code for readability.
ππ» Main.cppμμ μλ² μμλΆλΆμ μ°λ λλ‘ λΆλ¦¬νμ΅λλ€.
I separated the server startup part into a thread in Main.cpp.
ππ» βοΈλ‘ νμλ λΆλΆμ κΈ°μ‘΄μ½λμμ λ°λ λ΄μ©μ
λλ€.
The parts marked with βοΈ are the changes made to the existing code.
βοΈ Server.h
#include <string>
class Server {
public:
// μμ±μ: μλ² μ΄κΈ°ν (IP, Port)
// Constructor: Initialize server (IP, Port)
Server(const std::string& ip, int port);
// μλ² μμΌ νμΌ λμ€ν¬λ¦½ν°λ₯Ό μ μ₯ν λ©€λ² λ³μ
// Member variable to store server socket file descriptors
int server_fd = -1; // βοΈ
// μλ² μ€ν ν¨μ: 리μ€λμ μμνκ³ λ©μΈ 루νλ₯Ό λλ¦Ό
// Server execution function: Starts listening and runs the main loop
bool start();
// μλ² μ’
λ£ (νμνλ€λ©΄)
// Shut down the server (if necessary)
void stop();
private:
std::string ip_address;
int port_number;
// μ€μ 리μ€λ λ° μ°κ²° μμ λ‘μ§ (λ΄λΆ ꡬν)
// Actual listening and connection reception logic (internal implementation)
void run_listener();
// μ°κ²° μ²λ¦¬ λ‘μ§ (μ€λ λ ν λλ λ³λ νΈλ€λ¬μκ² μμ)
// Connection handling logic (delegated to thread pool or separate handler)
void handle_client(int client_socket);
};
βοΈ Server.cpp
#include "Server.h"
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <thread>
#include <vector>
//#define PORT 5080 βοΈ
#define BACKLOG 10 // λκΈ° ν ν¬κΈ° / wait queue size
Server::Server(const std::string& ip, int port)
: ip_address(ip), port_number(port) {}
void Server::run_listener() {
//std::cout << "[INFO] Server listening on " << ip_address << ":" << port_number << std::endl;
// --- 1. μμΌ μμ± (Socket Creation) --- //
//int server_fd = socket(AF_INET, SOCK_STREAM, 0);
// λ©€λ² λ³μλ‘ λ³κ²½ / Change to member variableβοΈ
server_fd = socket(AF_INET, SOCK_STREAM, 0);
//if (server_fd == 0) { βοΈ
if (server_fd == -1) {
perror("socket failed");
exit(EXIT_FAILURE);
}
int opt = 1;
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
// --- 2. λ°μΈλ© (Binding) --- //
struct sockaddr_in address;
address.sin_family = AF_INET; // IPv4
address.sin_addr.s_addr = INADDR_ANY; // λͺ¨λ μΈν°νμ΄μ€ IP μ¬μ© / Use all interface IPs
address.sin_port = htons(port_number); // ν¬νΈλ₯Ό λ€νΈμν¬ λ°μ΄νΈ μμλ‘ λ³ν / Convert ports to network byte order
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
close(server_fd);
exit(EXIT_FAILURE);
}
// --- 3. 리μ€λ μμ (setsockopt: listen_socket(socket)) --- //
if (listen(server_fd, BACKLOG) < 0) {
perror("listen failed");
close(server_fd);
exit(EXIT_FAILURE);
}
std::cout << "Server listening on port " << port_number << "..." << std::endl;
// --- 4. λ©μΈ 루ν (Accept loop): ν΄λΌμ΄μΈνΈ μ°κ²°μ 무νν κΈ°λ€λ¦Ό / Infinitely waiting for client connections --- //
while (true) {
// IPv4ꡬ쑰체 / Structure for IPv4 address
struct sockaddr_in client_address;
// μ£Όμ κ΅¬μ‘°μ²΄κ° λ©λͺ¨λ¦¬μμ μ°¨μ§νλ λ°μ΄νΈ ν¬κΈ°λ₯Ό μ μ₯νλ λ³μμ νμ
// Type of the variable storing the byte size occupied by the address structure in memory
socklen_t addrlen = sizeof(client_address);
// accept() ν¨μκ° λΈλ‘νΉ(Blocking) μνμμ ν΄λΌμ΄μΈνΈ μ°κ²°μ κΈ°λ€λ¦Ό
// The accept() function waits for client connections in a blocking state.
int client_socket = accept(server_fd, (struct sockaddr *)&client_address, &addrlen);
if (client_socket < 0) {
perror("accept failed");
continue; // μ€ν¨νμΌλ©΄ λ€μ 루νλ₯Ό λλ©° μ¬μλ / Retry in the next loop if it fails
}
// λμμ± μ²λ¦¬: μλ‘μ΄ μ°κ²°μ΄ μ€λ©΄ μλ‘μ΄ μ°λ λλ₯Ό μμ±νμ¬ μ²λ¦¬
// Concurrency Handling: When a new connection arrives, create a new thread to handle it.
//std::thread client_thread(Server::handle_client, client_socket);
//
// λλ€ {[](){...}} λ νμ¬ μ€λ λκ° Server κ°μ²΄(this)μ λ§₯λ½μ μ μ§νλ©° μ€νλλλ‘ λ³΄μ₯ν©λλ€.
// Lambda {[](){...}} ensures that the current thread executes while maintaining the context of the Server object (this).
std::thread client_thread([this, client_socket]() {
this->handle_client(client_socket);
});
// μ°λ λλ₯Ό λΆλ¦¬νκ³ λ©μΈ 루νλ₯Ό κ³μ μ€ννκ² ν¨
// Detach the thread so that the main loop continues running.
client_thread.detach();
}
}
//βοΈ
void Server::handle_client(int client_socket) {
char buffer[1024];
std::cout << "[Connection] New client connected." << std::endl;
// 1. λ°μ΄ν° μμ / receive data (Read)
ssize_t bytes_read = read(client_socket, buffer, sizeof(buffer) - 1);
if (bytes_read > 0) {
buffer[bytes_read] = '\0'; // C-string
std::string request = buffer;
std::cout << "[Received] " << request.substr(0, 30) << "..." << std::endl;
// 2. μλ΅ μ μ‘ / send response(Write)
const char* response = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n<h1>πHi~ Hi~ Hi~~~!</h1><p>Welcome to the miniWebserver!</p>";
write(client_socket, response, strlen(response));
}
// 3. μ°κ²° μ’
λ£ / close connection
close(client_socket);
std::cout << "[Connection] Client disconnected." << std::endl;
}
bool Server::start() {
// μλ²κ° μ€μ λ‘ μλνλ λ©μΈ ν¨μ / Main function that actually runs the server
try {
run_listener();
} catch (const std::exception& e) {
std::cerr << "[ERROR] Server failed to start: " << e.what() << std::endl;
return false;
}
return true;
}
void Server::stop() {
// μλ²λ₯Ό μ’
λ£νλ ν¨μ / Function to stop the server
//close(server_fd);βοΈ
if (server_fd != -1) {
// λ©€λ² λ³μμ μ μ₯λ κ°μ μ¬μ©νμ¬ μ’
λ£ν©λλ€. / Use the value stored in the member variable to stop the server
close(server_fd);
server_fd = -1; // λ«μμΌλ―λ‘ μ΄κΈ°ν / Initialize to -1 after closing
}
}
βοΈ Main.cpp
#include "Server.h"
#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>
#include <string>
int main() {
// 1. μλ² μΈμ€ν΄μ€ μμ± / Create server instance
Server my_server("127.0.0.1", 5080);
std::thread server_thread(&Server::start, &my_server); // μλ² μμ / Start server βοΈ
std::cout << "--- Starting Server Application ---" << std::endl;
// 2. μ’
λ£ λ‘μ§ (μλ²κ° μ’
λ£λμ§ μκΈ° λλ¬Έμ μ€νλμ§ μμ,λμ€μ μν μ’
λ£ λ‘μ§)
// Termination logic (not executed because the server has not terminated, termination logic for later)
server_thread.join();
my_server.stop();
return 0;
}
βοΈ μ»΄νμΌ / Compiling
g++ Server.cpp Main.cpp -o server -std=c++17 -pthread
βοΈμ€ν / Run
./server