Linux epoll并发服务器示例代码-c语言

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

int set_none_block(int fd)
{
	int flags = fcntl(fd, F_GETFL, 0);

	if (flags < 0)
	{
		perror("get F_GETFL failed");
		return -1;
	}

	int ret = fcntl(fd, F_GETFL, flags | O_NONBLOCK);
	if (ret < 0)
	{
		perror("set F_GETFL failed");
	}
	return ret;
}

int update_events(int efd, int fd, int events, int op)
{
	struct epoll_event ev = {0};

	memset(&ev, 0, sizeof(ev));
	ev.data.fd = fd;
	ev.events = events;
	printf("%s fd %d events read %d write %d\n", op == EPOLL_CTL_MOD ? "mod" : "add", fd, ev.events & EPOLLIN, ev.events & EPOLLOUT);
	int ret = epoll_ctl(efd, op, fd, &ev);
	if (ret < 0)
	{
		printf("epoll_ctl error:%s\n", strerror(errno));
	}
	return ret;
}

int handle_accept(int efd, int fd)
{
	struct sockaddr_in raddr = {0};

	socklen_t raddr_size = sizeof(raddr);
	int afd = accept(fd, (struct sockaddr *)&raddr, &raddr_size);
	if (afd < 0)
	{
		printf("accept faild\n");
		return -1;
	}

	struct sockaddr peer, local;
	socklen_t peer_size = sizeof(peer);
	int ret = getpeername(afd, (struct sockaddr *)&peer, &peer_size);
	if (ret < 0)
	{
		printf("getpeername failed\n");
		return -1;
	}

	printf("accept a connection from %s\n", inet_ntoa(raddr.sin_addr));
	set_none_block(afd);
	update_events(efd, afd, EPOLLIN | EPOLLOUT | EPOLLET, EPOLL_CTL_ADD);
	return 0;
}

int send_data(int fd, char *data, int len)
{
	int w = 0;

	while ((w = write(fd, data, len)) > 0)
	{
		data += w;
		len -= w;
	}

	if (w < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
	{
		printf("send failed:%s\n", strerror(errno));
		return -1;
	}

	return 0;
}

char testData[] = "HTTP/1.1 200 OK\r\nConnection: Keep-Alive\r\nContent-Type: t    ext/html; charset=UTF-8\r\nContent-Length: 1048576\r\n\r\n123456";

int recieve_data(int fd)
{
	int n = 0;
	char buff[4096] = {0};

	printf("handle recieve data ...\n");
	n = read(fd, buff, sizeof(buff));
	if (n < 0)
	{
		perror("read");
		return errno;
	}

	if (n == 0)
	{
		printf("fd %d is closed\n", fd);
		return errno;
	}

	if (n > 0 && n < sizeof(buff))
	{
		if (strstr(buff, "\r\n\r\n") != NULL)
		{
			char *p = malloc(2048 * 1024);
			if (p)
			{
				memset(p, 0, 2048 * 1024);
				strcpy(p, testData);
				int len = strlen(testData);
				for (int i = 0; i < 1048570; i++)
					p[len++] = 'A';
				write(fd, p, len);
				free(p);
			}
		}
		else
		{
			printf("read:%s\n", buff);
			write(fd, "ack:", 4);
			write(fd, buff, n);
		}
	}
	else if (n >= sizeof(buff))
	{
		printf("read too much data\n");
	}
	printf("handle recieve data end\n");
	return 0;
}

void loop_once(int efd, int lfd, int timeout)
{
	int maxEvts = 20;
	struct epoll_event activeEvts[100] = {0};

	int n = epoll_wait(efd, activeEvts, maxEvts, timeout);
	printf("epoll_wait return %d\n", n);
	for (int i = 0; i < n; i++)
	{
		int fd = activeEvts[i].data.fd;
		int ev = activeEvts[i].events;

		if (ev & (EPOLLIN | EPOLLERR))
		{
			if (fd == lfd)
				handle_accept(efd, fd);
			else
				recieve_data(fd);
		}
		else if (ev & EPOLLOUT)
		{
			printf("handle epollout\n");
			send_data(fd, "fuck the world\n", 15);
		}
		else
		{
			printf("unknown event\n");
			exit(-1);
		}
	}
}

void signal_handler(int signal)
{
	switch (signal)
	{
	case SIGPIPE:
		break;
	case SIGINT:
		printf("stop by user\n");
		exit(0);
		break;
	default:
		break;
	}
}

int main(int argc, char *argv[])
{
	signal(SIGINT, signal_handler);

	short port = 20000;
	int efd = epoll_create(1);
	if (efd < 0)
	{
		printf("create epoll failed\n");
		return -1;
	}

	int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (listen_fd < 0)
	{
		printf("create listen socket failed\n");
		return -1;
	}

	struct sockaddr_in addr = {0};
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = INADDR_ANY;

	int ret = bind(listen_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr));
	if (ret)
	{
		printf("bind to 0.0.0.0:%d failed %d, %s", port, errno, strerror(errno));
		return -1;
	}

	ret = listen(listen_fd, 20);
	if (ret)
	{
		printf("listen failed %d, %s", errno, strerror(errno));
		return -1;
	}
	printf("fd %d listen at %d\n", listen_fd, port);

	set_none_block(listen_fd);
	update_events(efd, listen_fd, EPOLLIN, EPOLL_CTL_ADD);
	for (;;)
	{
		loop_once(efd, listen_fd, 10000);
	}
	return 0;
}

You may also like...

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据