๐๐ป ์ด์ ์ฝ๋์์ ๊ฐ๋
์ฑ์ ์ํด์ ํ์ผ์ ๋ถ๋ฆฌํ์ต๋๋ค.
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