티스토리 뷰

728x90
IOCP, Boost.Asio, epoll 예제

IOCP, Boost.Asio, epoll 예제

1. IOCP (Windows)

플랫폼: Windows

설명: IOCP는 Windows에서 제공하는 비동기 I/O 처리 메커니즘으로, 고성능 네트워크 서버를 구축할 때 사용됩니다.

예제 코드:

        
#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <thread>
#include <vector>

#pragma comment(lib, "Ws2_32.lib")

struct ClientContext {
    OVERLAPPED overlapped;
    SOCKET socket;
    char buffer[1024];
};

void workerThread(HANDLE iocpHandle) {
    DWORD bytesTransferred;
    ULONG_PTR completionKey;
    LPOVERLAPPED overlapped;

    while (true) {
        BOOL result = GetQueuedCompletionStatus(
            iocpHandle, &bytesTransferred, &completionKey, &overlapped, INFINITE);

        if (!result || bytesTransferred == 0) {
            std::cerr << "클라이언트가 연결을 종료했습니다." << std::endl;
            continue;
        }

        auto* context = reinterpret_cast<ClientContext*>(completionKey);
        std::cout << "받은 메시지: " << context->buffer << std::endl;

        WSABUF wsabuf{bytesTransferred, context->buffer};
        DWORD sent;
        WSASend(context->socket, &wsabuf, 1, &sent, 0, &context->overlapped, nullptr);
    }
}

int main() {
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);

    SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    sockaddr_in serverAddr{};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_port = htons(8080);
    bind(serverSocket, reinterpret_cast<sockaddr*>(&serverAddr), sizeof(serverAddr));
    listen(serverSocket, SOMAXCONN);

    HANDLE iocpHandle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 0);

    std::vector<std::thread> threads;
    for (int i = 0; i < 4; ++i) {
        threads.emplace_back(workerThread, iocpHandle);
    }

    while (true) {
        SOCKET clientSocket = accept(serverSocket, nullptr, nullptr);
        auto* context = new ClientContext{};

        context->socket = clientSocket;
        CreateIoCompletionPort(reinterpret_cast<HANDLE>(clientSocket), iocpHandle,
                               reinterpret_cast<ULONG_PTR>(context), 0);

        WSARecv(clientSocket, nullptr, 0, nullptr, nullptr, &context->overlapped, nullptr);
    }

    for (auto& t : threads) {
        t.join();
    }

    closesocket(serverSocket);
    WSACleanup();
    return 0;
}
        
    

2. Boost.Asio (크로스 플랫폼)

플랫폼: Windows, Linux, macOS

설명: Boost.Asio는 플랫폼에 구애받지 않고 네트워크 및 비동기 I/O 처리를 쉽게 구현할 수 있는 라이브러리입니다.

예제 코드:

        
#include <boost/asio.hpp>
#include <iostream>
#include <memory>

using boost::asio::ip::tcp;

class Session : public std::enable_shared_from_this<Session> {
public:
    explicit Session(tcp::socket socket) : socket_(std::move(socket)) {}

    void start() {
        doRead();
    }

private:
    tcp::socket socket_;
    char buffer_[1024];

    void doRead() {
        auto self(shared_from_this());
        socket_.async_read_some(
            boost::asio::buffer(buffer_),
            [this, self](boost::system::error_code ec, std::size_t length) {
                if (!ec) {
                    doWrite(length);
                }
            });
    }

    void doWrite(std::size_t length) {
        auto self(shared_from_this());
        boost::asio::async_write(
            socket_, boost::asio::buffer(buffer_, length),
            [this, self](boost::system::error_code ec, std::size_t /*length*/) {
                if (!ec) {
                    doRead();
                }
            });
    }
};

class Server {
public:
    Server(boost::asio::io_context& io_context, short port)
        : acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) {
        doAccept();
    }

private:
    tcp::acceptor acceptor_;

    void doAccept() {
        acceptor_.async_accept(
            [this](boost::system::error_code ec, tcp::socket socket) {
                if (!ec) {
                    std::make_shared<Session>(std::move(socket))->start();
                }
                doAccept();
            });
    }
};

int main() {
    try {
        boost::asio::io_context io_context;
        Server server(io_context, 8080);
        io_context.run();
    } catch (std::exception& e) {
        std::cerr << "Exception: " << e.what() << "\n";
    }
    return 0;
}
        
    

3. epoll (Linux)

플랫폼: Linux

설명: epoll은 Linux에서 대규모 파일 디스크립터를 효율적으로 관리하는 이벤트 기반 I/O 메커니즘입니다.

예제 코드:

        
#include <sys/epoll.h>
#include <netinet/in.h>
#include <unistd.h>
#include <cstring>
#include <iostream>

int main() {
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);

    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(8080);
    bind(server_fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
    listen(server_fd, SOMAXCONN);

    int epoll_fd = epoll_create1(0);

    epoll_event event{}, events[10];
    event.events = EPOLLIN;
    event.data.fd = server_fd;
    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event);

    while (true) {
        int n = epoll_wait(epoll_fd, events, 10, -1);
        for (int i = 0; i < n; ++i) {
            if (events[i].data.fd == server_fd) {
                int client_fd = accept(server_fd, nullptr, nullptr);
                event.events = EPOLLIN;
                event.data.fd = client_fd;
                epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &event);
            } else {
                char buffer[1024];
                ssize_t bytes = read(events[i].data.fd, buffer, sizeof(buffer));
                if (bytes > 0) {
                    write(events[i].data.fd, buffer, bytes); // 에코
                } else {
                    close(events[i].data.fd);
                }
            }
        }
    }

    close(server_fd);
    return 0;
}
        
    
IOCP, Boost.Asio, epoll 예제

IOCP, Boost.Asio, epoll 예제

요약

기술 플랫폼 특징 장점 단점
IOCP Windows 비동기 완료 기반 I/O 처리 수십만 동시 연결 처리 가능 Windows 전용
Boost.Asio 크로스 플랫폼 고수준 비동기 I/O 이식성과 유연성 초기 러닝 커브 높음
epoll Linux 이벤트 기반 I/O CPU 및 메모리 효율적 Linux 전용

IOCP

플랫폼: Windows

빌드 방법:

  • Visual Studio에서 프로젝트 생성
  • #include <winsock2.h>#include <windows.h> 추가
  • Ws2_32.lib 라이브러리를 프로젝트에 링크

실행 방법: Visual Studio에서 빌드 후 실행.

        
        // Visual Studio 명령줄 빌드 예제:
        cl /EHsc /DWIN32 iocp_server.cpp /link Ws2_32.lib
        
    

Boost.Asio

플랫폼: 크로스 플랫폼 (Windows, Linux, macOS)

빌드 방법:

  • Boost 라이브러리 설치
  • g++ 또는 Visual Studio로 빌드

Linux/Mac:

        
        g++ -std=c++17 asio_server.cpp -o asio_server -lboost_system
        
    

Windows: Visual Studio에서 Boost 포함 설정 후 빌드.

실행 방법: 빌드된 실행 파일을 실행.

epoll

플랫폼: Linux

빌드 방법:

  • Linux에서 g++로 컴파일
        
        g++ -std=c++17 epoll_server.cpp -o epoll_server
        
    

실행 방법: 터미널에서 실행:

        
        ./epoll_server
        
    

결론

  • IOCP: Windows에서 최고 성능의 네트워크 서버를 구축할 때 적합.
  • Boost.Asio: 크로스 플랫폼 네트워크 애플리케이션 개발 시 추천.
  • epoll: Linux 환경에서 대규모 네트워크 처리를 필요로 할 때 사용.
반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함
250x250