[C/C++] epoll

yjseo·2024년 10월 29일



8월에 노션에 정리해가며 공부했던거임

epoll

🎯리눅스 운영체제에서 제공하는 효율적인 I/O 다중화 (multiplexing) 기법
🎯대규모 네트워크 서버나 성능 애플리케이션에서 동시에 여러 소켓이나 파일 디스크립터를 감시하고 처리할 때 사용

특징

I/O 다중화 (multiplexing)

  • 여러 파일 디스크립터를 동시에 감시하여 어느 하나라도 I/O 작업이 가능해지면 즉시 처리할 수 있도록 하는 기술
  • select, poll, epoll이 있고 epoll이 성능과 확장성이 가장 뛰어남

수신 대기 목록

  • 파일 디스크립터들을 감시하기 위해 사용
  • 커널 내부에 존재 -> 대규모 시스템에 효율적

epoll과 select비교


epoll API

#include <sys/epoll.h>

int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

epoll_create

운영체제가 관리하는 epoll 인스턴스라고 불리는 파일 디스크립터 저장소 생성

epoll_ctl

epoll에 파일 디스크립터들을 등록/수정/삭제 하는 함수

epoll_wait

관심 있는 파일 디스크립터에 어떤 이벤트가 발생했는지 조사


epoll 서버 예시

#include <cstdio>
#include <iostream>
#include <string.h>
#include <fcntl.h>

using namespace std;

#include <sys/unistd.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <arpa/inet.h>

#define LISTEN_BACKLOG 15
#define PORT 8000
#define SIZE 1024
#define MAX_EVENT 1024

int main() 
{
    int server_fd = socket(PF_INET, SOCK_STREAM, 0);
    
    struct sockaddr_in sock_addr;
    memset(&sock_addr, 0, sizeof(sock_addr));
    sock_addr.sin_family = AF_INET;
    sock_addr.sin_port = htons(PORT);
    sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    
    bind(server_fd, (struct sockaddr*)&sock_addr, sizeof(sockaddr_in));
    
    listen(server_fd, LISTEN_BACKLOG);
    
    // epoll 설정
    int epoll_fd = epoll_create(SIZE);
    
    struct epoll_event events;
    events.events = EPOLLIN | EPOLLET; // edge-trigger
    events.data.fd = server_fd;
    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &events);
    
    struct epoll_event epoll_events[MAX_EVENTS];
    int event_count;
    
    while (true)
    {
        event_count = epoll_wait(epoll_fd, epoll_events, MAX_EVENTS, -1);
        
        for (int i = 0; i < event_count; i++) 
        {
            if (epoll_events[i].data.fd == server_fd)
            {
                // 서버 소켓에서 발생한 이벤트 처리
                // 클라이언트의 연결 요청 수락
                
                int client_fd;
                int client_len;
                struct sockaddr_in client_addr;
                
                client_len = sizeof(client_addr);
                client_fd = accept(server_fd, 
                    (struct sockaddr*)&client_addr, 
                    (socklen_t*)&client_len);
                
                
                // 클라이언트 fd를 epoll에 등록
                struct epoll_event events;
                events.events = EPOLLIN | EPOLLET;
                events.data.fd = client_fd;
                
                epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &events);
            }
            else 
            {
                // 클라이언트 소켓에서 발생한 이벤트 처리
                // 주로 EPOLLIN 이벤트 발생
                
                // 클라이언트가 보낸 데이터를 읽거나 필요한 작업 수행
                ...
                
            }
        }
    }
}

참고
Select와 epoll 비교
🔗https://ozt88.tistory.com/21
Epoll 구현
🔗https://velog.io/@dltmdrl1244/%EC%86%8C%EC%BC%93%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D11-select%EB%B3%B4%EB%8B%A4-%EB%A7%9B%EC%9E%88%EB%8A%94-epoll
🔗https://mydevdiary.tistory.com/107
Epoll 예제 코드
🔗https://rammuking.tistory.com/entry/Epoll%EC%9D%98%EA%B8%B0%EC%B4%88%EA%B0%9C%EB%85%90-%EB%B0%8F-%EC%82%AC%EC%9A%A9-%EB%B0%A9%EB%B2%95

profile
저 뭐해먹고 살아요..🥺

0개의 댓글