IO多路复用(select/poll/epoll代码实现)

IO多路复用(select/poll/epoll代码实现)


前言

IO多路复用主要包括select、poll和epoll,以下附有这三种实现方式代码参考。


提示:以下是本篇文章正文内容,下面案例可供参考

一、select

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//#include <netinet/tcp.h>
#include <arpa/inet.h>

#include <errno.h>

#define BUF_LEN 1024

int main(int argc, char *argv[])
{
	if (argc < 2)
	{
		printf("param port error\n");
		return -1;
	}

	int port = atoi(argv[1]);

	int sockfd = socket(AF_INET, SOCK_STREAM, 0);

	struct sockaddr_in addr;
	memset(&addr, 0, sizeof(struct sockaddr_in));

	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = INADDR_ANY;

	if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0)
	{
		perror("bind\n");
		return -2;
	}

	if (listen(sockfd, 5) < 0)
	{
		perror("listen\n");
	}

	fd_set rfds, rset;

	FD_ZERO(&rfds);
	FD_SET(sockfd, &rfds);

	int maxfd = sockfd + 1;
	while (1)
	{
		rset = rfds;
		int nready = select(maxfd, &rset, NULL, NULL, NULL);
		if (nready < 0)
		{
			continue;
		}

		if (FD_ISSET(sockfd, &rset))
		{
			struct sockaddr_in clientaddr;
			socklen_t client_len = sizeof(clientaddr);

			int clientfd = accept(sockfd, (struct sockaddr*)&clientaddr, &client_len);
			if (clientfd <= 0)
			{
				continue;
			}

			FD_SET(clientfd, &rfds);

			if (clientfd >= maxfd)
			{
				maxfd = clientfd + 1;
			}

			printf("sockfd %d, maxfd %d, clientfd %d\n", sockfd, maxfd, clientfd);
			if (--nready == 0)
			{
				continue;
			}
		}

		int i = 0;
		for (i = sockfd + 1; i < maxfd; i++)
		{
			if (FD_ISSET(i, &rset))
			{
				char buffer[BUF_LEN] = {0};
				int ret = recv(i, buffer, BUF_LEN, 0);
				if (ret < 0)
				{
					if ((EAGAIN == errno) || (EWOULDBLOCK == errno))
					{
						printf("recv all data\n");
					}
					else
					{
						FD_CLR(i, &rfds);
						close(i);

						if (i == maxfd - 1)
						{
							maxfd--;
						}
						continue;
					}
				}
				else if (0 == ret)
				{
					printf("client close\n");
					FD_CLR(i, &rfds);
					close(i);
					if (i == maxfd - 1)
					{
						maxfd--;
					}
					continue;
				}
				else
				{
					printf("recv %d byte data, content is [%s]\n", ret, buffer);
				}

				if (--nready == 0) break;
			}
		}
	}

	return 0;
}

二、poll

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//#include <netinet/tcp.h>
#include <arpa/inet.h>

#include <errno.h>

#include <sys/poll.h>

#define BUF_LEN 1024
#define POLL_SIZE 1024


int main(int argc, char *argv[])
{
	if (argc < 2)
	{
		printf("param port error\n");
		return -1;
	}

	int port = atoi(argv[1]);

	int sockfd = socket(AF_INET, SOCK_STREAM, 0);

	struct sockaddr_in addr;
	memset(&addr, 0, sizeof(struct sockaddr_in));

	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = INADDR_ANY;

	if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0)
	{
		perror("bind\n");
		return -2;
	}

	if (listen(sockfd, 5) < 0)
	{
		perror("listen\n");
	}

	struct pollfd fds[POLL_SIZE] = {0};
	fds[0].fd = sockfd;
	fds[0].events = POLLIN;

	int maxfd = 1, i = 0;
	for (i = 1; i < POLL_SIZE; i++)
	{
		fds[i].fd = -1;
	}

	while (1)
	{
		int nready = poll(fds, maxfd, 5);
		if (nready <= 0) continue;

		if (POLLIN == (fds[0].revents & POLLIN))
		{
			struct sockaddr_in client_addr;
			memset(&client_addr, 0, sizeof(struct sockaddr_in));
			socklen_t client_len = sizeof(client_addr);

			int clientfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len);
			if (0 > clientfd)
			{
				continue;
			}

			char str[INET_ADDRSTRLEN] = {0};
			printf("recvived from %s at port %d, sockfd:%d, clientfd:%d\n",
				inet_ntop(AF_INET, &client_addr.sin_addr, str, sizeof(str)),
				ntohs(client_addr.sin_port),
				sockfd,
				clientfd);

			fds[clientfd].fd = clientfd;
			fds[clientfd].events = POLLIN;

			if (clientfd >= maxfd)
			{
				maxfd = clientfd + 1;
			}

			if (--nready == 0) continue;
		}
		
		for (i = 1;i < maxfd; i++)
		{
			if (fds[i].revents & (POLLIN|POLLERR))
			{
				char buffer[BUF_LEN] = {0};
				int ret = recv(i, buffer, BUF_LEN, 0);
				if (ret < 0)
				{
					if (errno == EAGAIN || errno == EWOULDBLOCK)
					{
						printf("read all data\n");
					}
					else
					{
						close(i);
						fds[i].fd = -1;
						if (i == maxfd - 1)
						{
							maxfd--;
						}
						continue;
					}
					
				}
				else if (ret == 0)
				{
					printf("disconnect %d\n", i);
					
					close(i);
					fds[i].fd = -1;
					if (i == maxfd - 1)
					{
						maxfd--;
					}
					continue;
				} else
				{
					printf("recv: %s, %d Bytes\n", buffer, ret);
				}
				if (--nready == 0) break;
			}
		}
	}

	return 0;
}

三、epoll



#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//#include <netinet/tcp.h>
#include <arpa/inet.h>

#include <errno.h>

#include <sys/epoll.h>

#define BUF_LEN 1024
#define EPOLL_SIZE 1024


int main(int argc, char *argv[])
{
	if (argc < 2)
	{
		printf("param port error\n");
		return -1;
	}

	int port = atoi(argv[1]);

	int sockfd = socket(AF_INET, SOCK_STREAM, 0);

	struct sockaddr_in addr;
	memset(&addr, 0, sizeof(struct sockaddr_in));

	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = INADDR_ANY;

	if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0)
	{
		perror("bind\n");
		return -2;
	}

	if (listen(sockfd, 5) < 0)
	{
		perror("listen\n");
	}

	int epoll_fd = epoll_create(EPOLL_SIZE);    /**<参数只有0和正数之分 */
	struct epoll_event ev, events[EPOLL_SIZE] = {0};

	ev.events = EPOLLIN;
	ev.data.fd = sockfd;
	epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sockfd, &ev);

	while (1)
	{
		int nready = epoll_wait(epoll_fd, events, EPOLL_SIZE, -1);
		if (nready == -1)
		{
			printf("epoll_wait\n");
			break;
		}

		int i = 0;
		for (i = 0; i < nready; i++)
		{
			if (events[i].data.fd == sockfd)
			{
				struct sockaddr_in client_addr;
				memset(&client_addr, 0, sizeof(struct sockaddr_in));
				socklen_t client_len = sizeof(client_addr);

				int clientfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len);
				if (0 > clientfd)
				{
					continue;
				}

				char str[INET_ADDRSTRLEN] = {0};
				printf("recvived from %s at port %d, sockfd:%d, clientfd:%d\n",
					inet_ntop(AF_INET, &client_addr.sin_addr, str, sizeof(str)),
					ntohs(client_addr.sin_port),
					sockfd,
					clientfd);

				ev.events = EPOLLIN | EPOLLET;
				ev.data.fd = clientfd;
				epoll_ctl(epoll_fd, EPOLL_CTL_ADD, clientfd, &ev);
			}
			else
			{
				int clientfd = events[i].data.fd;
				char buffer[BUF_LEN] = {0};
				int ret = recv(clientfd, buffer, BUF_LEN, 0);
				if (ret < 0)
				{
					if (errno == EAGAIN || errno == EWOULDBLOCK)
					{
						printf("read all data\n");
					}
					else
					{
						close(clientfd);
						ev.events = EPOLLIN | EPOLLET;
						ev.data.fd = clientfd;
						epoll_ctl(epoll_fd, EPOLL_CTL_DEL, clientfd, &ev);
						continue;
					}
					
				}
				else if (ret == 0)
				{
					printf("disconnect %d\n", clientfd);
					
					close(clientfd);
					ev.events = EPOLLIN | EPOLLET;
					ev.data.fd = clientfd;
					epoll_ctl(epoll_fd, EPOLL_CTL_DEL, clientfd, &ev);
					continue;
				} else
				{
					printf("recv: %s, %d Bytes\n", buffer, ret);
				}
			}
		}
	}

	return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值