多路复用之 epoll 的代码编写

本文介绍了一种高效的多路复用技术epoll,并提供了详细的C语言实现代码。通过设置非阻塞IO、监听读写事件等方式,epoll能够有效地处理大量并发连接。

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; }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值