#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
int main()
{
int error_check;
/*
socket : 소켓 생성
*/
int server_fd = socket(PF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
printf("socket() error\n");
return 0;
}
// server fd Non-Blocking Socket으로 설정
int flags = fcntl(server_fd, F_GETFL);
// flag 추가
flags |= O_NONBLOCK;
// fd에 대해서 F_SETFL cmd를 사용하는데 flags를 arg로 설정
if (fcntl(server_fd, F_SETFL, flags) < 0) {
printf("server_fd fcntl() error\n");
return 0;
}
// 소켓 옵션 설정
int option = true;
error_check = setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
if (error_check < 0) {
printf("setsockopt() error[%d]\n", error_check);
close(server_fd);
return 0;
}
// 소켓 속성 설정
struct sockaddr_in mSockAddr;
memset(&mSockAddr, 0, sizeof(mSockAddr));
mSockAddr.sin_family = AF_INET;
mSockAddr.sin_port = htons(1818);
mSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 사용가능한 랜카드 IP 사용
/*
bind : 소켓 속성과 소켓 fd 연결
*/
error_check = bind(server_fd, (struct sockaddr*)&mSockAddr, sizeof(mSockAddr));
if (error_check < 0) {
printf("bind() error[%d]\n", error_check);
close(server_fd);
return 0;
}
/*
listen : 응답 대기
*/
if (listen(server_fd, LISTEN_BACKLOG) < 0) {
printf("listen() error\n");
close(server_fd);
return 0;
}
/*
Epoll fd 생성
*/
int epoll_fd = epoll_create(1024); // size 만큼의 커널 폴링 공간을 만드는 함수
if (epoll_fd < 0) {
printf("epoll_create() error\n");
close(server_fd);
return 0;
}
// server fd, epoll에 등록
struct epoll_event events;
events.events = EPOLLIN | EPOLLET;
events.data.fd = server_fd;
/*
server events set
*/
// epoll_ctl : epoll이 관심을 가져주기 바라는 FD와 발생하는 event를 등록하는 인터페이스
// EPOLL_CTL_ADD : 관심있는 파일디스크립트 추가
// EPOLL_CTL_MOD : 기존 파일 디스크립터를 수정
// EPOLL_CTL_DEL : 기존 파일 디스크립터를 관심 목록에서 삭제
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &events) < 0) {
printf("epoll_ctl() error\n");
close(server_fd);
close(epoll_fd);
return 0;
}
/*
epoll wait
*/
// 관심있는 fd들에 무슨일이 일어났는지 조사
// 사건들의 리스트를 epoll_events[]의 배열로 전달
// 리턴값은 사건들의 개수, 사건의 최대 개수는 MAX_EVENTS
int MAX_EVENTS = 1024;
struct epoll_event epoll_events[MAX_EVENTS];
int event_count;
int timeout = -1;
while (true)
{
event_count = epoll_wait(epoll_fd, epoll_events, MAX_EVENTS, timeout);
if (event_count < 0) {
printf("epoll_wait() error [%d]\n", event_count);
return 0;
}
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;
printf("User Accept\n");
client_len = sizeof(client_addr);
/*
Accept
*/
client_fd = accept(server_fd, (struct sockaddr*)&client_addr, (socklen_t*)&client_len);
// client fd Non-Blocking Socket으로 설정
int flags = fcntl(client_fd, F_GETFL);
flags |= O_NONBLOCK;
if (fcntl(client_fd, F_SETFL, flags) < 0) {
printf("client_fd[%d] fcntl() error\n", client_fd);
return 0;
}
if (client_fd < 0) {
printf("accept() error [%d]\n", client_fd);
continue;
}
// 클라이언트 fd, epoll 에 등록
struct epoll_event events;
events.events = EPOLLIN | EPOLLET;
events.data.fd = client_fd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &events) < 0) {
printf("client epoll_ctl() error\n");
close(client_fd);
continue;
}
}
else
{
// epoll에 등록 된 클라이언트들의 send data 처리
int str_len;
int client_fd = epoll_events[i].data.fd;
char data[4096];
str_len = read(client_fd, &data, sizeof(data));
if (str_len == 0) {
// 클라이언트 접속 종료 요청
printf("Client Disconnect [%d]\n", client_fd);
close(client_fd);
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, NULL);
}
else {
// 접속 종료 요청이 아닌 경우 요청의 내용에 따라 처리.
printf("Recv Data from [%d]\n", client_fd);
}
}
}
}
}
댓글남기기