[게임 서버] 3.8 epoll
카테고리: GameServer
태그: GameServer
📦 3. 소켓 프로그래밍
👉🏻 항목 8: epoll
🔍 epoll이란?
정의:
- epoll은 소켓이 I/O 가능 상태가 되면 감지하여 사용자에게 어떤 소켓이 I/O 가능 상태인지 알려준다
💻 epoll 기본 사용법
epoll = new epoll(); // 1
foreach(s in sockets) {
epoll.add(s, GetUserPtr(s)); // 2
}
events = epoll.wait(100ms); // 3
foreach(event in events) { // 4
s = event.socket; // 5
userPtr = event.UserPtr;
type = event.type; // 송신 or 수신
if(type == ReceiveEvent) {
(result, data) = s.recv();
if(data.length > 0) {
Proceess(userPtr, s, data);
}
}
}
동작 과정:
- 1번: epoll 객체 생성
- 2번: epoll에 여러 소켓 추가
- 각 소켓의 I/O 가능 이벤트 감지 가능
- 각 소켓의 소켓 소유자 객체 등 원하는 값 삽입 가능
- 3번: epoll에서 이벤트들을 꺼내오는 함수
wait()호출- 원하는 시간(100ms)까지 블로킹하고, 이전에 이벤트가 생기면 즉시 리턴
- 4번: 각 이벤트들의 소켓 객체와 사용자 정의 값 가져오기
- 5번: 원하는 처리 진행
⚠️ 레벨 트리거의 문제점
문제 상황:
- 실행해보면 소켓의 송신 버퍼가 빈 공간을 유지하는 시간이 짧다
- 즉, 대부분의 경우는 송신 가능이다
- 필요 이상의 루프를 돌기에 불필요한 CPU 연산 낭비가 일어난다
⚡ 엣지 트리거 (Edge Trigger)
레벨 트리거 vs 엣지 트리거:
- 레벨 트리거: I/O 가능 상태(1)를 계속 감지
- 엣지 트리거: 변화가 있음(0→1, 1→0)을 감지
장점:
- 이를 사용하면 I/O 가능으로 바뀔 때만 꺼낼 수 있다
🚨 엣지 트리거 사용 시 주의사항
문제 상황:
- 소켓에 데이터그램이 2개가 생기고, 엣지 트리거(0→1)가 발생한다
- 소켓에서 데이터그램을 꺼내고, 남은 데이터그램은 1개가 된다
- 레벨이 1에서 내려오지 않아 고장난다
해결법:
- I/O 호출을 would block이 발생할 때까지 반복해야 한다
- 소켓은 논블록으로 설정되어 있어야 한다
✅ 엣지 트리거 올바른 구현
...
foreach(event in events) {
s = event.socket;
userPtr = event.UserPtr;
type = event.type; // 송신 or 수신
if(type == ReceiveEvent) {
while(true) { // 엣지 트리거(0->1) 활성화 시, 반복
(result, data) = s.recv();
if(data.length > 0) {
Proceess(userPtr, s, data);
}
// 이제 소켓에서 모든 데이터그램을 꺼낸다.
if(result == EWOULDBLOCK) break;
}
}
}
핵심:
- would block이 발생할 때까지 계속 데이터를 꺼내야 한다
- 이를 통해 소켓 버퍼를 완전히 비운다
🔌 connect()/accept()의 I/O 가능 이벤트
...
foreach(event in events) {
s = event.socket;
userPtr = event.UserPtr;
type = event.type; // 송신 or 수신
if(type == ReceiveEvent) {
if(s가 리스닝 소켓이면)
s2 = s.accept();
else
s.recv();
}
}
처리 방법:
- 리스닝 소켓인 경우
accept()호출 - 일반 소켓인 경우
recv()호출
🧐 정리
| 구분 | 레벨 트리거 | 엣지 트리거 |
|---|---|---|
| 감지 방식 | I/O 가능 상태 유지 감지 | I/O 가능 상태 변화 감지 |
| 이벤트 발생 | 상태가 1이면 계속 발생 | 0→1 또는 1→0 변화 시만 발생 |
| CPU 사용 | 높음 (불필요한 반복) | 낮음 (변화 시만 처리) |
| 구현 복잡도 | 간단 | 복잡 (would block까지 반복 필요) |
| 소켓 설정 | 블로킹/논블록 모두 가능 | 논블록 필수 |
핵심 포인트:
- epoll은 여러 소켓의 I/O 이벤트를 효율적으로 감지하는 메커니즘이다
- 레벨 트리거는 구현이 간단하지만 불필요한 CPU 낭비가 발생한다
- 엣지 트리거는 효율적이지만 would block까지 반복 처리해야 한다
- 엣지 트리거 사용 시 반드시 논블록 소켓으로 설정해야 한다
accept()와recv()이벤트를 구분하여 처리해야 한다
댓글남기기