epoll是实现多路复用最有效率的方式,没有之一。
以下是它的编写代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static void Usage(const char* proc)
{
assert(proc);
printf("Usage: %s [ip] [port]\n", proc);
}
static int set_nonblock(int fd)
{
int fl = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, fl|O_NONBLOCK);
}
int my_read(int fd, char* buf, int len)
{
assert(buf);
ssize_t total = 0;
ssize_t s = 0;
while( (s = read(fd, &buf[total], len - 1 - total)) > 0 && errno != EAGAIN)
{
total += s;
}
return total;
}
int start_up(const char* ip, int port)
{
assert(ip);
assert(port > 0);
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
{
perror("socket");
exit(3);
}
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = inet_addr(ip);
if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
{
perror("bind");
exit(4);
}
if(listen(sock, 5) < 0)
{
perror("listen");
exit(5);
}
return sock;
}
int main(int argc, char* argv[])
{
if(argc < 3)
{
Usage(argv[0]);
return 1;
}
int listen_sock = start_up(argv[1], atoi(argv[2]));
int epfd = epoll_create(256);
if(epfd < 0)
{
perror("epoll_create");
return 2;
}
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = listen_sock;
epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev);
int nums = 0;
struct epoll_event ready_events[64];
int len = 64;
int timeout = -1;
while(1)
{
switch( (nums = epoll_wait(epfd, ready_events, len, timeout)) )
{
case 0://timeout
printf("timeout...\n");
break;
case -1://error
perror("epoll_wait");
break;
default://success
{
int i = 0;
for( ; i < nums; ++i)
{
int fd = ready_events[i].data.fd;
if( fd == listen_sock && (ready_events[i].events & EPOLLIN))
{
//new link...
struct sockaddr_in client;
socklen_t len = sizeof(client);
int new_fd = accept(listen_sock,\
(struct sockaddr*)&client, &len);
if( new_fd < 0)
{
perror("accept");
continue;
}
printf("get a new client: %s:%d\n",\
inet_ntoa(client.sin_addr),\
ntohs(client.sin_port));
ev.events = EPOLLIN | EPOLLET;//read
ev.data.fd = new_fd;
set_nonblock( new_fd );
epoll_ctl(epfd, EPOLL_CTL_ADD, new_fd, &ev);
}
else
{
//normal IO
if(ready_events[i].events & EPOLLIN)
{
char buf[1024];
//my_read(fd, buf)
ssize_t s = read(fd, buf, sizeof(buf) - 1);
if(s > 0)
{
buf[s] = 0;
printf("client# %s\n", buf);
//read data done...
ev.events = EPOLLOUT | EPOLLET;
ev.data.fd = fd;
epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev);
}
else if( s == 0)
{
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
close(fd);
printf("client close...\n");
}
else
{
perror("read");
}
}
else if(ready_events[i].events & EPOLLOUT)
{
char buf[1024];
sprintf(buf,"HTTP/1.0 200 OK\r\n\r\n
hello bit & world -_-||
");
//mywrite();
write(fd, buf, strlen(buf));
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
close(fd);
}
else
{}
}
}
}
break;
}
}
return 0;
}