[Webserver]miniWebserver(thread detach->join)-(10)

๐Ÿ‘‰๐Ÿป ์ฃผ์š” ๋ณ€๊ฒฝ์‚ฌํ•ญ์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.
The major changes are as follows.

โœ”๏ธ โ—๏ธ ํ‘œ์‹œ๋œ ๋ถ€๋ถ„์ด ๋ณ€๊ฒฝ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค.
The parts marked with โ—๏ธ are the changes.

โœ”๏ธ 5080์€http ์„œ๋ฒ„์ด๊ณ  6443์€ https์„œ๋ฒ„์ž…๋‹ˆ๋‹ค. 6080์„œ๋ฒ„๋Š” ์‚ญ์ œํ–ˆ์Šต๋‹ˆ๋‹ค.
5080 is an HTTP server and 6443 is an HTTPS server. Server 6080 has been deleted.

โœ”๏ธ์„œ๋ฒ„ ์ข…๋ฃŒ์‹œ์—๋„ handle_clientํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜์–ด “[SSL] SSL_new() failed”๋ฉ”์„ธ์ง€ ์ถœ๋ ฅ๋˜๋Š” ๋ฌธ์ œ๋ฅผ ๊ต์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.
Fixed an issue where the handle_client function was executed and the “[SSL] SSL_new() failed” message was displayed even when the server was terminated.

— ์„œ๋ฒ„ ์ข…๋ฃŒ ์‹œ์ ์— ssl_ctx๊ฐ€ ํ•ด์ œ๋˜์–ด ๊ธฐ์กด์— ์ž‘์—… ์ค‘์ด๊ฑฐ๋‚˜ ์žฌ์‹คํ–‰๋˜๋˜ ์Šค๋ ˆ๋“œ์—์„œ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
There was an issue where ssl_ctx was released at the time of server shutdown, causing errors in existing working or restarted threads.

— ๋ชจ๋“  ์Šค๋ ˆ๋“œ๋ฅผ ํ•ด์ œํ•œ ํ›„ ssl_ctx๋ฅผ ํ•ด์ œ๋ฅผ ์‹คํ–‰ํ•จ์œผ๋กœ์จ ์˜ค๋ฅ˜๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.
I resolved the error by releasing ssl_ctx after releasing all threads.

โœ”๏ธ ์˜ค๋ฅ˜ ๋ฉ”์„ธ์ง€๋Š” SSL (https)์‚ฌ์šฉํ•˜๋Š” HttpsServer.cpp์—์„œ ๋ฐœ์ƒํ–ˆ์ง€๋งŒ http๋„ ๋™์ผํ•˜๊ฒŒ ๊ตฌ์กฐ๋ฅผ ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.
The error message occurred in HttpsServer.cpp using SSL (https), but the structure was changed in the same way for http.

โœ”๏ธ exit ๋ช…๋ น์–ด๋กœ ์„œ๋ฒ„ ์ข…๋ฃŒ์‹œ ์Šค๋ ˆ๋“œ๊ฐ€ ์™„์ „ํžˆ ์ •๋ฆฌ๋˜๊ธฐ๊นŒ์ง€ ์•ฝ๊ฐ„์˜ ์‹œ๊ฐ„์ด ์†Œ์š”๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
When terminating the server with the exit command, it may take some time for threads to be completely cleaned up.

๐Ÿ‘‰๐Ÿป์ฝ”๋“œ / Code

โœ”๏ธ ์Šค๋ ˆ๋“œ ๋ฐฑํ„ฐ์„ ์–ธ / Thread vector declaration

— HttpServer.h์— ์Šค๋ ˆ๋“œ๋ฅผ ์˜ฎ๊ฒจ ๋‹ด์„ ๋ฐฑํ„ฐ๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.
Declare a vector to store threads in HttpServer.h.

std::vector<std::thread> client_threads;

โœ”๏ธ ๋ฃจํ”„ํƒˆ์ถœ,์Šค๋ ˆ๋“œ ์ €์žฅ / Loop escape, thread save

— HttpsServer.cpp,Server.cpp

— running.load() ๊ฐ€ false์ด๋ฉด while๋ฃจํ”„ ํƒˆ์ถœํ•˜๊ณ  ์Šค๋ ˆ๋“œ๋ฅผ ๋ฐฑํ„ฐ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
If running.load() is false, exit the while loop and save the thread to the vector.

    while (running.load()) {

        // ๋ฃจํ”„ํƒˆ์ถœ / Loop escape โ—๏ธ
        if (!running.load()) {
            break;  // ์ข…๋ฃŒ ์‹ ํ˜ธ ๋ฐ›์œผ๋ฉด ๋ฃจํ”„ ์ข…๋ฃŒ / Terminate the loop when the termination signal is received.
        }

        ... ์ค‘๋žต / skipping the middle...

        if (running.load() && client_socket < 0) {

            // ๋ฃจํ”„ํƒˆ์ถœ / Loop escape โ—๏ธ
            if (!running.load()) {
                break;  // ์†Œ์ผ“ ๋‹ซํ˜€์„œ ์‹คํŒจํ•œ ๊ฒฝ์šฐ ์ข…๋ฃŒ / Terminate if failed due to socket closing
            }

            perror("accept failed");
            continue; 
        }
        // ํด๋ผ์ด์–ธํŠธ ์ ‘์† / Client connected
        std::thread client_thread([this, client_socket]() {

            //์™ธ๋ถ€์—์„œ ๋ฉ”์„ธ์ง€ ๋ฐ”๊พธ๊ธฐ / Change message externally
            this->handle_client(client_socket);
        });
        // ์Šค๋ ˆ๋“œ - ๋ฐฑํ„ฐ์— ์ €์žฅ / Thread - Stored in a vectorโ—๏ธ
        client_threads.push_back(std::move(client_thread));

        //client_thread.detach(); // ์ด์ „์ฝ”๋“œ / previous codeโ—๏ธ
    }

โœ”๏ธ ์Šค๋ ˆ๋“œ ์ข…๋ฃŒ ํ›„ ssl_ctx์‹คํ–‰
Execute ssl_ctx after thread termination

— for๋ฌธ์œผ๋กœ ๋ฐฑํ„ฐ์— ์ €์žฅ๋œ ์Šค๋ ˆ๋“œ๋ฅผ ํ•˜๋‚˜์”ฉ ์‚ฌ์šฉ์ค‘์ธ์ง€ ํ™•์ธ(joinable()ํ•˜๊ณ  ์‚ฌ์šฉ์ค‘์ด ์•„๋‹ˆ๋ฉด(joinable() == true) ์Šค๋ ˆ๋“œ๊ฐ€ ์ข…๋ฃŒ๋ ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ(join())ํ•ฉ๋‹ˆ๋‹ค.
Use a for loop to check each thread stored in the vector one by one if it is in use (joinable()), and if it is not in use (joinable() == true), wait until the thread terminates (join()).

— ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ๋Œ€๊ธฐ์ƒํƒœ๊ฐ€๋˜๋ฉด ์Šค๋ ˆ๋“œ๋ฅผ ์ข…๋ฃŒ ํ•ฉ๋‹ˆ๋‹ค.(client_threads.clear();)
Terminates threads when all threads are in a waiting state.(client_threads.clear();)

— ์Šค๋ ˆ๋“œ ์ข…๋ฃŒ๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ssl_ctx๋ฅผ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค.
Release ssl_ctx when thread termination is complete.

— HttpsServer.cpp stop() ํ•จ์ˆ˜ / function

void https::Server::stop() {
  try {
    if (running.load() && server_fd != -1) { 

        ... ์ค‘๋žต / skipping the middle ...

        // ๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ ์Šค๋ ˆ๋“œ ์ข…๋ฃŒ ๋Œ€๊ธฐโ—๏ธโ—๏ธ
        for (auto& t : client_threads) {
            if (t.joinable()) {
                t.join();
            }
        }
        client_threads.clear();

        // SSL ์ปจํ…์ŠคํŠธ ํ•ด์ œ (์กด์žฌํ•œ๋‹ค๋ฉด) /  Release SSL context (if any)
         if (ssl_ctx) {
            SSL_CTX_free(ssl_ctx);
            ssl_ctx = nullptr;
        }

        // OpenSSL ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ •๋ฆฌ / OpenSSL Library Cleanup โ—๏ธโ—๏ธ
        // OpenSSL 3.x์—์„œ๋Š” ๋ณ„๋„์˜ ์ •๋ฆฌ ํ•จ์ˆ˜ ํ˜ธ์ถœ ๋ถˆํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
        //EVP_cleanup();

        std::cout << "[Server] Shutdown initiated." << std::endl;
    }
      } catch (const std::exception& e) {
            std::cerr << "[ERROR] Exception during shutdown: " << e.what() << std::endl;
    } catch (...) {
            std::cerr << "[ERROR] Unknown exception during shutdown." << std::endl;
    }
}

๐Ÿ‘‰๐Ÿป ๋นŒ๋“œ / Build

cd build
cmake ..
make

๐Ÿ‘‰๐Ÿป ์‹คํ–‰ / Run

./main

๐Ÿ‘‰๐Ÿป ํ„ฐ๋ฏธ๋„ ์‹คํ–‰ ๊ฒฐ๊ณผ / Terminal execution result

MacBookAir build % ./main
[SSL] SSL context successfully initialized
--- Starting Server Application ---
Server listening on port 5080...
Https Server listening on port 6443...
CMD> exit
[INFO] ์ข…๋ฃŒ ๋ช…๋ น์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค. ์„œ๋น„์Šค ์ข…๋ฃŒ๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
[INFO] Received a shutdown command. Starting service shutdown.
[Server] Shutdown initiated.
[Server] Shutdown initiated.
[MAIN] Server Application Finished.
MacBookAir build % 

Leave a Reply