基于Linux epoll模型的Simple

关于epoll的介绍以及与其它I/O模型的优缺点,各大网站论坛均有介绍,这里就不多说了;

本Simple使用了epoll的边缘出发模式(ET),支持多客户端连接;

首先定义自己的数据结构以及相关全局变量:

#define MAX_EVENTS 10
#define MAX_BUFFER_SIZE 1024
#define LISTEN_PORT 8000

struct global_data
{
	int server_sock;
	int server_epoll;

};

struct client_data
{
	char *read_buf;
	char *write_buf;
	int read_len;
	int read_off;
	int write_len;
	int write_off;
	int fd;
	struct sockaddr_in addr;
};

struct global_data g_gd;

client_data结构体用来存储和处理客户端上下文数据;

下面初始化一个新的客户端上下文结构:

struct client_data *alloc_client_data(int fd, struct sockaddr_in *addr = NULL)
{
	struct client_data *cd = NULL;

	cd = (struct client_data *)malloc(sizeof(struct client_data));
	if(cd == NULL)
	{
		return NULL;
	}
	memset(cd, 0, sizeof(struct client_data));

	cd->fd = fd;
	cd->write_len = MAX_BUFFER_SIZE;
	cd->write_off = 0;
	cd->read_len = MAX_BUFFER_SIZE;
	cd->read_off = 0;
	cd->write_buf = (char *)malloc(cd->write_len + 1);
	cd->read_buf = (char *)malloc(cd->read_len + 1);
	assert(cd->write_buf);
	assert(cd->read_buf);
	if(addr) memcpy(&cd->addr, addr, sizeof(cd->addr));
	
	return cd;
}
释放客户端上下文数据:

void free_client_data(struct client_data *cd)
{
	if(cd == NULL) return ;

	close(cd->fd);
	if(cd->write_buf) free(cd->write_buf);
	if(cd->read_buf) free(cd->read_buf);

	free(cd);

	return ;
}
设置socket为非阻塞模式:

int set_sock_non_block(int fd)
{
	int flags, result;

	flags = fcntl(fd, F_GETFL, 0);
	if(flags == -1)
	{
		return -1;
	}
	flags |= O_NONBLOCK;
	result = fcntl(fd, F_SETFL, flags);
	if(result == -1)
	{
		return -1;
	}

	return 0;
}
处理客户端连接请求:

int accept_client()
{
	int ret = -1;
	int addrlen;
	int client_sock;
	struct sockaddr_in remote_addr;
	struct epoll_event e_event;

	do
	{
		while(1)
		{
			addrlen = sizeof(struct sockaddr_in);
			client_sock = accept(g_gd.server_sock, (struct sockaddr *)&remote_addr, (socklen_t *)&addrlen);
			if(client_sock == -1)
			{
				if(errno == EAGAIN || errno == EWOULDBLOCK)
				{
					break;
				}
				else
				{
					printf("accept failed, error: %s \n", strerror(errno));
					break;
				}
			}
			else
			{
				set_sock_non_block(client_sock);

				struct client_data *cd = alloc_client_data(client_sock, &remote_addr);
				assert(cd);
				e_event.events = EPOLLIN | EPOLLET;
				e_event.data.ptr = cd;
				if(epoll_ctl(g_gd.server_epoll, EPOLL_CTL_ADD, client_sock, &e_event) == -1)
				{
					printf("epoll_ctl client failed \n");
					free_client_data(cd);
				}
				else
				{
					printf("accept client: %s:%d \n", inet_ntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port));
				}
			}
		}

		ret = 0;

	}while(0);

	return ret;
}
接收客户端数据:

int recv_data(struct client_data *client)
{
	int ret = -1;
	int len_recv = 0;
	struct epoll_event e_event;

	if(client == NULL) return -1;

	do
	{
		while(1)
		{
			len_recv = recv(client->fd, client->read_buf, client->read_len, 0);
			if(len_recv == -1)
			{
				if(errno == EAGAIN)
				{
					break;
				}
				else
				{
					free_client_data(client);
					break;
				}
			}
			else if(len_recv == 0)
			{
				printf("client closed connection!!! \n");
				free_client_data(client);
				break;
			}
			else
			{
				client->read_buf[len_recv] = '\0';
				printf("[%s:%d] recv data: %s:%d \n", 
						inet_ntoa(client->addr.sin_addr), 
						ntohs(client->addr.sin_port),
						client->read_buf,
						len_recv);

				client->read_off = len_recv;

				// send response
				strcpy(client->write_buf, "OK!");
				client->write_off = strlen(client->write_buf);

				e_event.events = EPOLLOUT | EPOLLET;
				e_event.data.ptr = client;
				epoll_ctl(g_gd.server_epoll, EPOLL_CTL_MOD, client->fd, &e_event);
			}
		}

		ret = 0;
	}while(0);

	return ret;
}
发送数据给客户端:

int send_data(struct client_data *client)
{
	int ret = -1;
	int len_send = 0;
	struct epoll_event e_event;

	if(client == NULL) return -1;

	do
	{
		len_send = send(client->fd, client->write_buf, client->write_off, 0);
		if(len_send == -1)
		{
			if(errno != EAGAIN)
			{
				printf("send error %s \n", strerror(errno));
				free_client_data(client);
			}
		}
		else if(len_send == 0)
		{
			free_client_data(client);
		}
		else
		{
			e_event.events = EPOLLIN | EPOLLET;
			e_event.data.ptr = client;
			epoll_ctl(g_gd.server_epoll, EPOLL_CTL_MOD, client->fd, &e_event);
		}

		ret = 0;

	}while(0);

	return ret;
}
服务器主程:

void epoll_server()
{
	int len_recv;
	int len_send;
	int len_sin;
	int signal_count;
	struct sockaddr_in local_addr;
	struct epoll_event e_event;
	struct epoll_event e_events[MAX_EVENTS];
	char buff[MAX_BUFFER_SIZE];

	memset(&g_gd, '\0', sizeof(struct global_data));
	memset(buff, '\0', sizeof(buff));

	do
	{
		// create server socket
		g_gd.server_sock = socket(AF_INET, SOCK_STREAM, 0);
		if(g_gd.server_sock < 0)
		{
			printf("create socket failed \n");
			break;
		}

		// bind
		local_addr.sin_family = AF_INET;
		local_addr.sin_addr.s_addr = INADDR_ANY;
		local_addr.sin_port = htons(LISTEN_PORT);
		if(bind(g_gd.server_sock, (struct sockaddr *)&local_addr, sizeof(local_addr)) == -1 )
		{
			printf("bind socket failed \n");
			break;
		}

		// set non-block
		if(set_sock_non_block(g_gd.server_sock) == -1)
		{
			printf("set_sock_non_block failed \n");
			break;
		}

		// listen
		if(listen(g_gd.server_sock, SOMAXCONN) == -1)
		{
			printf("listen fialed \n");
			break;
		}

		// create epoll handle
		g_gd.server_epoll = epoll_create(MAX_EVENTS);
		if(g_gd.server_epoll < 0)
		{
			printf("epoll create failed \n");
			break;
		}

		// register server socket event
		e_event.events = EPOLLIN | EPOLLET;
		e_event.data.fd = g_gd.server_sock;
		if(epoll_ctl(g_gd.server_epoll, EPOLL_CTL_ADD, g_gd.server_sock, &e_event) < 0)
		{
			printf("epoll_ctl failed \n");
			break;
		}

		while(1)
		{
			printf("epoll wait... \n");
			signal_count = epoll_wait(g_gd.server_epoll, e_events, MAX_EVENTS, -1);
			if(signal_count == -1)	{ printf("epoll_wait failed \n"); break; }

			printf("wait signals: %d \n", signal_count);
			for(int i=0; i<signal_count; ++i)
			{
				if(e_events[i].events & EPOLLERR || e_events[i].events & EPOLLHUP)
				{
					printf("socket error occured \n");
					continue;
				}
				else if(e_events[i].data.fd == g_gd.server_sock)
				{
					accept_client();
				}
				else if(e_events[i].events & EPOLLIN)
				{
					recv_data((struct client_data *)e_events[i].data.ptr);
				}
				else if(e_events[i].events & EPOLLOUT)
				{
					send_data((struct client_data *)e_events[i].data.ptr);
				}
				else
				{
					printf("Some error happend \n");
				}
			}
		}

	}while(0);

	close(g_gd.server_sock);
	close(g_gd.server_epoll);

	return ;
}









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值