간단한 에코 서버
여러 클라이언트를 동시에 처리해 보세요.
간단한 에코 서버은(는) CoddyKit의 무료 C Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 C Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. C Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
만들어 볼 것
에코 서버는 TCP 연결을 수락하고 클라이언트가 보낸 바이트를 그대로 돌려보냅니다. 네트워크 프로그래밍의 "hello world"와 같은 예제입니다.
epoll을 사용해 단일 스레드가 여러 클라이언트를 동시에 처리하도록 만들겠습니다. 구성 요소는 수신 대기 소켓, epoll 루프, 클라이언트별 읽은 후 쓰기 처리입니다.
수신 대기 소켓 생성하기
IPv4 TCP 엔드포인트에는 socket()부터 사용합니다. 세 인수는 AF_INET, SOCK_STREAM, 프로토콜 0입니다.
이 호출은 파일 디스크립터를 반환합니다. 이 디스크립터를 바인딩하고 논블로킹으로 설정한 뒤, 마지막으로 epoll에 등록합니다. 모든 시스템 호출에서 -1인지 확인하세요.
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd == -1) { perror("socket"); exit(1); }주소 재사용하기
바인딩하기 전에 setsockopt()로 SO_REUSEADDR을 설정합니다. 그러면 TIME_WAIT 상태가 끝날 때까지 기다리지 않고 서버를 재시작해 같은 포트에 다시 바인딩할 수 있습니다.
이 설정이 없으면 빠르게 재시작할 때 EADDRINUSE 오류가 자주 발생해 개발 중 당황하게 됩니다.
int yes = 1;
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);포트에 바인딩하기
패밀리, 포트, 주소를 사용해 struct sockaddr_in을 채웁니다. 포트에는 htons()를 사용하고, 모든 인터페이스에서 수신하려면 INADDR_ANY를 사용합니다.
그런 다음 bind()를 호출해 소켓을 해당 주소에 연결합니다. htons는 호스트 바이트 순서를 네트워크 바이트 순서로 변환하며, 이 변환은 필수입니다.
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(8080);
bind(listen_fd, (struct sockaddr*)&addr, sizeof addr);수신 대기 및 논블로킹 설정
listen()을 호출해 소켓을 수동 소켓으로 표시하고 대기 중인 연결을 위한 대기열 크기를 설정합니다. SOMAXCONN은 시스템 최대값을 요청합니다.
그런 다음 소켓을 논블로킹으로 전환해 accept()가 이벤트 루프를 멈추지 않도록 합니다. 이제 epoll에 등록할 준비가 되었습니다.
listen(listen_fd, SOMAXCONN);
set_nonblocking(listen_fd);수신 대기 소켓 등록하기
epoll 인스턴스를 만들고 수신 대기 소켓을 EPOLLIN과 함께 추가합니다. 여기서 읽기 가능 이벤트가 발생하면 새 클라이언트가 수락되기를 기다리고 있다는 뜻입니다.
루프 안에서 수신 대기 소켓을 식별할 수 있도록 fd를 data.fd에 저장합니다.
int epfd = epoll_create1(0);
struct epoll_event ev = { .events = EPOLLIN, .data.fd = listen_fd };
epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &ev);클라이언트 수락하기
수신 대기 소켓을 읽을 수 있게 되면 EAGAIN이 반환될 때까지 accept()를 반복 호출합니다. 새 클라이언트 소켓은 각각 논블로킹으로 설정하고 EPOLLIN을 감시하도록 등록합니다.
이제부터 epoll은 해당 클라이언트가 에코할 수 있는 데이터를 보낼 때마다 알려 줍니다.
int c = accept(listen_fd, NULL, NULL);
if (c != -1) {
set_nonblocking(c);
struct epoll_event cev = { .events = EPOLLIN, .data.fd = c };
epoll_ctl(epfd, EPOLL_CTL_ADD, c, &cev);
}에코 로직
준비된 클라이언트에서 recv()로 버퍼에 데이터를 읽습니다. 바이트를 받으면 같은 바이트를 send()로 즉시 돌려보냅니다.
이 간단한 읽은 후 쓰기가 에코 동작입니다. 실제 환경에서는 전송되지 않은 바이트를 버퍼에 보관해야 하지만, 예제에서는 작은 응답이 전송 버퍼에 들어간다고 가정합니다.
char buf[4096];
ssize_t r = recv(fd, buf, sizeof buf, 0);
if (r > 0) {
send(fd, buf, r, 0);
}연결 끊김 감지하기
recv()의 반환값이 0이면 클라이언트가 정상적으로 연결을 종료한 것입니다. EAGAIN 이외의 값과 함께 음수가 반환되면 실제 오류입니다.
두 경우 모두 디스크립터를 epoll에서 제거하고 close()로 닫아 자원을 해제하고 추가 이벤트를 중지합니다.
if (r == 0 || (r < 0 && errno != EAGAIN)) {
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
close(fd);
}전체 루프
구성 요소를 합칩니다. 이벤트를 기다리고, 디스크립터가 수신 대기 소켓인지 클라이언트인지에 따라 분기한 뒤 그에 맞게 처리합니다.
이 간결한 루프는 완전히 작동하는 동시 에코 서버입니다. 스레드 하나로 여러 클라이언트를 처리하며 연결마다 별도의 스레드를 만들지 않습니다.
for (;;) {
int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
for (int i = 0; i < n; i++) {
if (events[i].data.fd == listen_fd) accept_clients();
else echo_or_close(events[i].data.fd);
}
}테스트 및 다음 단계
Linux에서 컴파일하고 nc localhost 8080으로 연결해 보세요. 입력하는 내용이 그대로 돌아옵니다. 여러 터미널을 열어 동시 처리를 확인해 보세요.
더 견고하게 만들려면 일부만 전송된 데이터를 버퍼링하고, EPOLLOUT을 처리하며, 완전히 데이터를 읽어 내는 EPOLLET 방식으로 전환하고, 반쪽 닫기를 나타내는 EPOLLRDHUP을 처리하세요.
빠른 확인
에코 서버의 흐름을 얼마나 이해했는지 확인해 보세요.
복습
epoll 에코 서버를 구축하셨습니다. 생성하고, SO_REUSEADDR을 설정하고, 바인드하고, 리슨한 다음 논블로킹으로 전환했습니다. 리스너를 등록하고, 반복문에서 클라이언트를 수락한 뒤 recv()/send()로 에코했습니다.
0 반환은 연결 해제로 처리하고 깔끔하게 닫으시면 됩니다. 이 뼈대에서 고성능 단일 스레드 네트워크 서버로 확장해 나갈 수 있습니다.
자주 묻는 질문
“간단한 에코 서버” 강의는 무료인가요?
네 — “간단한 에코 서버” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 C Academy 강의 전체를 잠금 해제할 수 있습니다. C Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“간단한 에코 서버”에서 뭘 배우나요?
여러 클라이언트를 동시에 처리해 보세요. 브라우저에서 직접 실행하는 실습 코드로 C Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
C Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 C Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.
“간단한 에코 서버” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 C Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 C Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 블로킹과 논블로킹 I/O
- epoll 설정하기
- 이벤트 루프
- 간단한 에코 서버