Linux epoll机制简单实例

<span style="font-size:18px;"><span style="font-size:18px;">server.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <errno.h>
#include <sys/epoll.h>
#include <fcntl.h>

#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 8000

#define MAX_RECV_LEN 1024
#define MAX_CLIENT_NUM 30
#define MAX_EVENT MAX_CLIENT_NUM</span>
#define BACK_LOG 20

static int running = 1;

int set_non_block (int fd)
{
	int flags, s;

	flags = fcntl (fd, F_GETFL, 0);
	if (flags == -1)
	{
		perror ("fcntl");
		return -1;
	}

	flags |= O_NONBLOCK;
	s = fcntl (fd, F_SETFL, flags);
	if (s == -1)
	{
		perror ("fcntl");
		return -1;
	}

	return 0;
}

int main (int argc, char *argv[])</span>
{
<span style="white-space:pre">	</span>int sock_fd = -1;
	int ret = -1;
	struct sockaddr_in serv_addr;
	struct sockaddr_in cli_addr;
	socklen_t serv_addr_len = 0;
	socklen_t cli_addr_len = 0;
	char recv_buf[MAX_RECV_LEN];
	int new_conn_fd = -1;
	int i = 0;
	int max_fd = -1;
	int num = -1;
	int ep_fd = -1;

	memset (&serv_addr, 0, sizeof (serv_addr));
	memset (&cli_addr, 0, sizeof (cli_addr));

	sock_fd = socket (AF_INET, SOCK_STREAM, 0);
	if (sock_fd < 0)
	{
		perror ("Fail to socket");
		exit (1);
	}

	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons (SERVER_PORT);
	serv_addr.sin_addr.s_addr = inet_addr (SERVER_IP);

	unsigned int value = 1;
	if (setsockopt (sock_fd, SOL_SOCKET, SO_REUSEADDR, (void *) &value, sizeof (value)) < 0)
	{
		perror ("Fail to setsockopt");
		exit (1);
	}

	serv_addr_len = sizeof (serv_addr);
	if (bind (sock_fd, (struct sockaddr *) &serv_addr, serv_addr_len) < 0)
	{
		perror ("Fail to bind");
		exit (1);
	}
	if (listen (sock_fd, BACK_LOG) < 0)
	{
		perror ("Fail to listen");
		exit (1);
	}

	set_non_block (sock_fd);//epoll使用边缘触发模式时要将监听的描述符设置成非阻塞

	ep_fd = epoll_create (MAX_EVENT);//epoll建立
	if (ep_fd < 0)
	{
		perror ("Fail to epoll_create");
		exit (1);
	}

	struct epoll_event ev, ev_ready[MAX_EVENT];

	bzero (&ev, sizeof (ev));
	ev.data.fd = sock_fd;
	ev.events = EPOLLIN | EPOLLET;

	ret = epoll_ctl (ep_fd, EPOLL_CTL_ADD, sock_fd, &ev);//加入监听描述符
	if (ret < 0)
	{
		perror ("Fail to epoll_ctl");
		exit (1);
	}

	char buf[1024];
	int len;
	int timeout = 5000;			//ms
	while (running)
	{

		bzero (&ev_ready, sizeof (ev_ready));
		ret = epoll_wait (ep_fd, ev_ready, MAX_EVENT, timeout);

		if (ret == 0)
		{
			printf ("timeout\n");
		}
		else if (ret < 0)
		{
			printf ("error occur\n");
		}
		else
		{
			for (i = 0; i < ret; i++)
			{

				if (ev_ready[i].data.fd == sock_fd)
				{
					printf ("new client comes\n");
					len = sizeof (cli_addr);
					new_conn_fd = accept (sock_fd, (struct sockaddr *) &cli_addr, &len);
					if (new_conn_fd < 0)
					{
						perror ("Fail to accept");
						exit (1);
					}
					else
					{
						set_non_block (new_conn_fd);
						ev.data.fd = new_conn_fd;
						ev.events = EPOLLIN | EPOLLET;
						epoll_ctl (ep_fd, EPOLL_CTL_ADD, new_conn_fd, &ev);
					}

				}
				else
				{
					if (ev_ready[i].events & EPOLLIN)
					{
						int fd = ev_ready[i].data.fd;
						memset (recv_buf, 0, MAX_RECV_LEN);
						{
							num = read (fd, recv_buf, MAX_RECV_LEN);
							if (num < 0)
							{
								printf ("Client(%d) left\n", fd);
								ev.data.fd = fd;
								ev.events = EPOLLIN | EPOLLET;
								epoll_ctl (ep_fd, EPOLL_CTL_DEL, fd, &ev);
								close (fd);
							}
							else if (num > 0)
							{
								recv_buf[num] = '\0';
								printf ("Recieve client(%d) data\n", fd);
								printf ("Data: %s\n\n", recv_buf);
							}
							if (num == 0)
							{
								printf ("Client(%d) exit\n", fd);
								ev.data.fd = fd;
								ev.events = EPOLLIN | EPOLLET;
								epoll_ctl (ep_fd, EPOLL_CTL_DEL, fd, &ev);//删除描述符

								close (fd);
							}
						}
					}
				}
			}
		}
	}
	return 0;
}

client.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/select.h>

#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 8000

#define MAX_RECV_LEN 1024

static int running = 1;

int main (int argc, char *argv[])
{
	int sock_fd = -1;
	int ret = -1;
	struct sockaddr_in serv_addr;
	struct sockaddr_in cli_addr;
	socklen_t serv_addr_len = 0;

	memset (&serv_addr, 0, sizeof (serv_addr));

	sock_fd = socket (AF_INET, SOCK_STREAM, 0);
	if (sock_fd < 0)
	{
		perror ("Fail to socket");
		exit (1);
	}

	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons (SERVER_PORT);
	serv_addr.sin_addr.s_addr = inet_addr (SERVER_IP);

	serv_addr_len = sizeof (serv_addr);
	if (connect (sock_fd, (struct sockaddr *) &serv_addr, serv_addr_len) < 0)
	{
		perror ("Fail to connect");
		exit (1);
	}
	char buf[1024];
	int num = 0;
	while (running)
	{
		num = read (STDIN_FILENO, buf, MAX_RECV_LEN);
		if (num > 0)
		{
			buf[num] = '\0';
			printf ("buf: %s\n", buf);
			num = write (sock_fd, buf, num);
			if (num < 0)
			{
				printf ("write failed\n");
				exit (1);
			}

			if (strncmp (buf, "exit", strlen ("exit")) == 0)
			{
				printf ("Client exit\n");
				close (sock_fd);
				return 0;
			}
		}
	}
	return 0;
}

Makefile:
all: client server
	gcc -o client client.c
	gcc -o server server.c
</span></span>

服务端log:

timeout
new client comes
Recieve client(5) data
Data: hello




timeout
new client comes
timeout
Recieve client(6) data
Data: hello




timeout
Client(6) exit
timeout
new client comes
timeout
Client(5) exit
timeout

猜你喜欢

转载自blog.csdn.net/szkbsgy/article/details/50670587