1. 程式人生 > >IO多路轉接之epoll

IO多路轉接之epoll

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <fcntl.h>

int start_up(char* ip, short port)
{
	int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
	if (listen_sock < 0)
	{
		perror("socket");
		exit(2);
	}

	struct sockaddr_in local;
	local.sin_family = AF_INET;
	local.sin_port = htons(port);
	local.sin_addr.s_addr = inet_addr(ip);
	if (bind(listen_sock, (struct sockaddr*)&local, sizeof(local)))
	{
		perror("bind");
		exit(3);
	}
	
	if (listen(listen_sock, 5) < 0)
	{
		perror("listen");
		exit(4);
	}

	return listen_sock;
}

void Usage(const char* 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 main(int argc, char* argv[])
{
	if (argc != 3)
	{
		Usage(argv[0]);
		exit(1);
	}

	int listen_sock = start_up(argv[1], atoi(argv[2]));
	
	int epfd = epoll_create(256);
	if (epfd < 0)
	{
		perror("epoll_create");
		exit(5);
	}

	struct epoll_event ev;
	ev.events = EPOLLIN;
	ev.data.fd = listen_sock;
	// 註冊唯一檔案描述符:關注讀事件
	epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev);

	struct epoll_event ready_events[64];
	int timeout = -1;
	while (1)
	{
		int num = epoll_wait(epfd, ready_events, 64, timeout);	
		if (num < 0)
		{
			perror("epoll_wait");
		}
		else if (num == 0)
		{
			printf("timeout...\n");
		}
		else
		{
			int i = 0;
			for (; i < num; i++)
			{
				// listen_sock 就緒
				int new_fd = ready_events[i].data.fd;
				if (new_fd == listen_sock && (ready_events[i].events & EPOLLIN))
				{
					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");
					}
					else
					{
						printf("get a new connect: %s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));

						ev.events = EPOLLIN;
						ev.data.fd = new_fd;
						epoll_ctl(epfd, EPOLL_CTL_ADD, new_fd, &ev);
					}
				}
				else if (ready_events[i].events & EPOLLIN)	// normal events
				{
					char buf[1024];
					ssize_t s = read(new_fd, buf, sizeof(buf)-1);
					if (s < 0)
					{
						perror("read");
					}
					else if (s == 0)
					{
						printf("client closed...\n");	
						epoll_ctl(epfd, EPOLL_CTL_DEL, new_fd, NULL);
						close(new_fd);
					}
					else
					{
						buf[s] = 0;
						printf("clinet# %s\n", buf);

						ev.events = EPOLLOUT | EPOLLET;
						ev.data.fd = new_fd;
						epoll_ctl(epfd, EPOLL_CTL_MOD, new_fd, &ev);				
					}
				}
				else if (ready_events[i].events & EPOLLOUT)
				{
					char buf[1024];
					strcpy(buf, "HTTP/1.0 200 OK\r\n\r\n<html><h1>hello world ! =_=||</h1></html>");
					write(new_fd, buf, strlen(buf));
					epoll_ctl(epfd, EPOLL_CTL_DEL, new_fd, NULL);
					close(new_fd);
				}
			}
		}
	} // while


	return 0;
}