<epoll>
#include <stdio.h>
#include <stdlib.h>#include <string.h>
#include <sys/socket.h>
#include <sys/epoll.h> // epoll system call 쓰기위한 헤더
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#define MAXPENDING 5
#define BUFSIZE 256
#define MAXSOCKET 10000 // 감시할 최대 소켓 수
/* 임의로 정의한 소켓, 버퍼를 가지는 구조체 */
typedef struct
{
int fd;
char buffer[BUFSIZE];
} epoll_data;
int eventpoll; // epoll 디스크립터
struct epoll_event serv_event; // 서버쪽 소켓에대한 epoll 세팅 구조체
struct epoll_event ev[MAXSOCKET]; // 클라이언트 소켓들을 관리하기 위한 구조체
int serv_sock,clnt_sock;
int connection=0;
void DieWithError(char *string)
{
perror(string);
exit(1);
}
int main(int argc, char *argv[])
{
int nready,n;
ssize_t nread;
socklen_t clnt_len;
epoll_data *data;
struct sockaddr_in serv_addr;
struct sockaddr_in clnt_addr;
unsigned short serv_port;
unsigned int set = 1;
if(argc!=2)
{
fprintf(stderr,"Usage: %s <Server Port>\n",argv[0]);
exit(1);
}
serv_port=atoi(argv[1]);
/* 소켓 생성 */
serv_sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
serv_addr.sin_port=htons(serv_port);
setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set));
if(bind(serv_sock,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0)
DieWithError("bind() error");
/* epoll 디스크립터 생성 */
if((eventpoll=epoll_create(MAXSOCKET))<0)
DieWithError("epoll_create error");
if(listen(serv_sock,MAXPENDING)<0)
DieWithError("listen() error");
/* 소켓을 논블록킹 방식으로 변경 */
if(fcntl(serv_sock,F_SETFL,O_NONBLOCK)<0)
DieWithError("set non-blocking error");
/* 서버쪽 소켓에 대한 epoll 셋팅 */
serv_event.events=EPOLLIN|EPOLLET; // 읽기, 경계인식방식으로 셋팅
serv_event.data.fd=serv_sock; // 서버 소켓 셋팅
/* epoll에 소켓과 감시할 이벤트를 등록 */
if(epoll_ctl(eventpoll,EPOLL_CTL_ADD,serv_sock,&serv_event)<0)
DieWithError("epoll_ctl error");
for(;;)
{
/*
감시하고 있는 소켓에서 변화 감지 ,
감지된 소켓 수를 리턴
변화감지된 소켓의 정보는 순서대로 ev구조체 배열에 저장
*/
nready = epoll_wait(eventpoll, ev, MAXSOCKET, -1);
if(nready<0)
DieWithError("epoll_wait error");
/* 변화가 생긴 수만큼 루프 수행 */
for(n=0;n<nready;n++)
{
/* 변화가 생긴 소켓이 서버 소켓인지 조사 (서버 소켓에 읽기 변화가 감지된 경우) */
if(ev[n].data.fd == serv_sock)
{
struct epoll_event event;
clnt_len=sizeof(clnt_addr);
/* accept */
if((clnt_sock=accept(serv_sock,(struct sockaddr *)&clnt_addr,&clnt_len))<0)
DieWithError("accept() failed");
/* 클라이언트의 소켓도 논블럭으로 지정 */
if(fcntl(clnt_sock,F_SETFL,O_NONBLOCK)<0)
DieWithError("set non-blocking error");
data=(epoll_data*)malloc(sizeof(epoll_data));
/* 읽기 감지, 경계인식 방식 */
event.events= EPOLLIN | EPOLLET;
data->fd=clnt_sock;
memset(data->buffer,0,sizeof(data->buffer));
/* epoll_event 구조체의 포인터가 사용자가 만든 소켓-버퍼 구조체를 가리키게 한다 */
event.data.ptr=data;
/* 클라이언트 소켓을 epoll에 등록 */
if(epoll_ctl(eventpoll,EPOLL_CTL_ADD,clnt_sock,&event)<0)
DieWithError("epoll_ctl error");
printf("client[%d] connected (Address: %s)\n",clnt_sock-4,inet_ntoa(clnt_addr.sin_addr));
}
/* 클라이언트 소켓에 변화가 생긴 경우 */
else
{
/* epoll 에 저장된 사용자 데이터를 복구 */
data=ev[n].data.ptr;
if((nread=recv(data->fd,data->buffer,sizeof(data->buffer),0))<0)
{
/* 응답이 없는 경우 */
if (errno==ECONNRESET)
{
printf("client[%d] aborted connection\n",data->fd-4);
/* epoll에서 제거 */
if(epoll_ctl(eventpoll,EPOLL_CTL_DEL,data->fd,ev)<0)
DieWithError("epoll_ctl error");
close(data->fd);
} else
DieWithError("read error");
/* 접속 종료 */
} else if(nread==0) {
printf("client[%d] closed connection\n",data->fd-4);
/* epoll에서 제거 */
if(epoll_ctl(eventpoll,EPOLL_CTL_DEL,data->fd,ev)<0)
DieWithError("epoll_ctl error");
close(data->fd);
} else {
if(send(data->fd,data->buffer,strlen(data->buffer),0)!=strlen(data->buffer))
DieWithError("send() error");
}
}
}
}
}
'Computer > Network' 카테고리의 다른 글
Loopback interface를 설정하는 이유 (0) | 2008.02.13 |
---|---|
The Border Gateway Protocol (BGP) (0) | 2007.11.26 |
Open Shortest Path First (OSPF) protocol (0) | 2007.11.26 |
네트워크 설정 : command line 에서. (0) | 2007.07.04 |
ICMP programming example (0) | 2007.06.12 |