epoll实现服务端异步通信

epoll_create 

open an epoll file descriptor
SYNOPSIS
#include <sys/epoll.h>
int epoll_create(int size)

DESCRIPTION
Open an epoll file descriptor by requesting the kernel allocate an event backing store dimensioned for size descriptors. The size is not the maximum size of the backing store but just a hint to the kernel about how to dimension internal structures. The returned file descriptor will be used for all the subsequent calls to
the epoll interface. The file descriptor returned by epoll_create(2) must be closed by using close(2).
RETURN VALUE
When successful, epoll_create(2) returns a non-negative integer identifying the descriptor. When an error occurs, epoll_create(2) returns -1 and errno is set appropriately.
ERRORS
EINVAL size is not positive.
ENFILE The system limit on the total number of open files has been reached.
ENOMEM There was insufficient memory to create the kernel object.
CONFORMING TO epoll_create(2) is a new API introduced in Linux kernel 2.5.44. The interface should be finalized by Linux kernel 2.5.66.

创建句柄或者文件描述符,特别注意,epoll并不是所有的内核版本都支持

epoll_ctl

control interface for an epoll descriptor
SYNOPSIS
#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
DESCRIPTION
Control an epoll descriptor, epfd, by requesting that the operation op be performed on the target file descriptor, fd. The event describes the object linked to the
file descriptor fd. The struct epoll_event is defined as :
typedef union epoll_data
{
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;
struct epoll_event {
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};

EVENT
The events member is a bit set composed using the following available event types :
EPOLLIN
    The associated file is available for read(2) operations.
EPOLLOUT
The associated file is available for write(2) operations.
EPOLLRDHUP
Stream socket peer closed connection, or shut down writing half of connection. (This flag is especially useful for writing simple code to detect peer shutdown when using Edge Triggered monitoring.)
EPOLLPRI
There is urgent data available for read(2) operations.
EPOLLERR
Error condition happened on the associated file descriptor. epoll_wait(2) will always wait for this event; it is not necessary to set it in events.
EPOLLHUP
Hang up happened on the associated file descriptor. epoll_wait(2) will always wait for this event; it is not necessary to set it in events.
EPOLLET
Sets the Edge Triggered behaviour for the associated file descriptor. The default behaviour for epoll is Level Triggered. See epoll(7) for more detailed information about Edge and Level Triggered event distribution architectures.
EPOLLONESHOT (since kernel 2.6.2)
Sets the one-shot behaviour for the associated file descriptor. This means that after an event is pulled out with epoll_wait(2) the associated file descriptor is internally disabled and no other events will be reported by the epoll interface. The user must call epoll_ctl(2) with EPOLL_CTL_MOD to reenable the  file descriptor with a new event mask.
The epoll interface supports all file descriptors that support poll(2). Valid values for the op parameter are :
EPOLL_CTL_ADD
Add the target file descriptor fd to the epoll descriptor epfd and associate the event event with the internal file linked to fd.
EPOLL_CTL_MOD
Change the event event associated with the target file descriptor fd.
EPOLL_CTL_DEL
Remove the target file descriptor fd from the epoll file descriptor, epfd. The event is ignored and can be NULL (but see BUGS below).
RETURN VALUE
When successful, epoll_ctl(2) returns zero. When an error occurs, epoll_ctl(2) returns -1 and errno is set appropriately.
ERRORS
EBADF epfd or fd is not a valid file descriptor.
EEXIST op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already in epfd.
EINVAL epfd is not an epoll file descriptor, or fd is the same as epfd, or the requested operation op is not supported by this interface.
ENOENT op was EPOLL_CTL_MOD or EPOLL_CTL_DEL, and fd is not in epfd.
ENOMEM There was insufficient memory to handle the requested op control operation.
EPERM The target file fd does not support epoll.
CONFORMING TOepoll_ctl(2) is a new API introduced in Linux kernel 2.5.44. The interface should be finalized by Linux kernel 2.5.66.
BUGS
In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required a non-NULL pointer in event, even though this argument is ignored. Since kernel 2.6.9, event can be specified as NULL when using EPOLL_CTL_DEL.

事件注册,将监控的描述符加入监控或者取消监控

epoll_wait 

wait for an I/O event on an epoll file descriptor
SYNOPSIS
#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event * events,int maxevents, int timeout);

DESCRIPTION
Wait for events on the epoll file descriptor epfd for a maximum time of timeout milliseconds. The memory area pointed to by events will contain the events that will be available for the caller. Up to maxevents are returned by epoll_wait(2). The maxevents parameter must be greater than zero. Specifying a timeout of -1 makes epoll_wait(2) wait indefinitely, while specifying a timeout equal to zero makes epoll_wait(2) to return immediately even if no events are available (return code equal to zero). The struct epoll_event is defined as :
typedef union epoll_data {
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;
struct epoll_event {
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
The data of each returned structure will contain the same data the user set with a epoll_ctl(2) (EPOLL_CTL_ADD,EPOLL_CTL_MOD) while the events member will contain the returned event bit field.
RETURN VALUE
When successful, epoll_wait(2) returns the number of file descriptors ready for the requested I/O, or zero if no file descriptor became ready during the requested
timeout milliseconds. When an error occurs, epoll_wait(2) returns -1 and errno is set appropriately.
ERRORS
EBADF epfd is not a valid file descriptor.
EFAULT The memory area pointed to by events is not accessible with write permissions.
EINTR The call was interrupted by a signal handler before any of the requested events occurred or the timeout expired.
EINVAL epfd is not an epoll file descriptor, or maxevents is less than or equal to zero.
CONFORMING TO epoll_wait(2) is a new API introduced in Linux kernel 2.5.44. The interface should be finalized by Linux kernel 2.5.66.

常用形式:

struct epoll_event ev, *events;
for(;;)
{
	nfds = epoll_wait(kdpfd, events, maxevents, -1);
	for(n = 0; n < nfds; ++n)
	{
		if(events[n].data.fd == listener)
		{
			client = accept(listener, (struct sockaddr *) &local,&addrlen);
			if(client < 0)
			{
				perror("accept");
				continue;
			}
			setnonblocking(client);
			ev.events = EPOLLIN | EPOLLET;
			ev.data.fd = client;
			if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) < 0)
			{
				fprintf(stderr, "epoll set insertion error: fd=%d\n",client);
					return -1;
			}
		}
		else
			do_use_fd(events[n].data.fd);
	}
}
我写的代码

[fy@localhost socket_epoll]$ less epoll.c 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <fcntl.h>

#define RELEASE
#define DEBUG
#define MYPORT 80    // the port users will be connecting to

#define BACKLOG 5     // how many pending connections queue will hold
#ifndef INFTIM
#define INFTIM -1
#endif
#define BUF_SIZE 500000
#define MAXLINE 100
#define MAXCLIENT 5
int fd_access[BACKLOG];    // accepted connection fd
int conn_amount;    // current connection amount
int recv_number=0;
void setnonblocking(int sock)
{
        int opts;
        opts=fcntl(sock,F_GETFL);
        if(opts<0)
        {
                perror("fcntl(sock,GETFL)");
                exit(1);
        }
        opts = opts|O_NONBLOCK;
        if(fcntl(sock,F_SETFL,opts)<0)
        {
                perror("fcntl(sock,SETFL,opts)");
                exit(1);
        }
}

int main(void)
{
        int sock_fd, new_fd,len,listen_fd;  // listen on sock_fd, new connection on new_fd
        struct sockaddr_in server_addr;    // server address information
        struct sockaddr_in client_addr; // connector's address information
        socklen_t sin_size;
        char buf[BUF_SIZE];
        int result;
        int i,j;
        int maxsock=0;
        int conn_fd,epfd,n;
        #ifdef DEBUG 
                printf("hello debug\n");
        #endif
        if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
        {
                perror("socket");
                exit(1);
        }
        setnonblocking(listen_fd);
        server_addr.sin_family = AF_INET;         // host byte order
        server_addr.sin_port = htons(MYPORT);     // short, network byte order
        server_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
        memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero));
        if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) 
        {
                perror("bind");
                exit(1);
        }
        if (listen(listen_fd, BACKLOG) == -1) 
        {
                perror("listen");
                exit(1);
        }
        #ifdef DEBUG
                printf("listen port %d  listen_fd  %d\n", MYPORT,listen_fd);
        #endif
        //epoll
        struct epoll_event ev,events[20];
        epfd=epoll_create(1024);
        printf("%d---%d\n",epfd,epoll_create(600));
        ev.data.fd=listen_fd;
        ev.events=EPOLLIN|EPOLLET;
        epoll_ctl(epfd,EPOLL_CTL_ADD,listen_fd,&ev);

        ev.data.fd=12;
        ev.events=EPOLLIN|EPOLLET;
        epoll_ctl(epfd,EPOLL_CTL_ADD,listen_fd,&ev);
        sin_size = sizeof(client_addr);
        #ifdef DEBUG
                printf("EPOLLIN---%d",EPOLLIN);
        #endif
        while (1) 
        {
                result=epoll_wait(epfd,events,20,-1);
                #ifdef DEBUG
                        printf("the total number is %d\n",recv_number);
                        printf("result is %d \n",result);
                #endif
                for(i = 0; i <result; i++)
                {
                        #ifdef DEBUG
                                printf("--------------print events----------------\n");
                                for(j=0;j<result;j++)
                                {
                                        printf("j events    %d\n",events[j].events);
                                        printf("j data fd   %d\n",events[j].data.fd);
                                }
                                printf("--------------print events  over-----------\n");
                        #endif
                        if(events[i].data.fd==listen_fd)
                        {
                                new_fd=accept(listen_fd,(struct sockaddr*)&client_addr,&sin_size);                      
                                while(new_fd>0)
                                {
                                        #ifdef DEBUG    
                                                printf("new_fd -------%d\n",new_fd);
                                                setnonblocking(new_fd);
                                        #endif
                                        ev.data.fd=new_fd;
                                        ev.events=EPOLLIN|EPOLLET;
                                        epoll_ctl(epfd,EPOLL_CTL_ADD,new_fd,&ev);
                                        new_fd=accept(listen_fd,(struct sockaddr*)&client_addr,&sin_size);
                                }
                        }
                        else if(events[i].events&EPOLLIN)
                        {
                                #ifdef DEBUG
                                        printf("mark  %d\n",events[i].data.fd);
                                #endif
                                if ( (sock_fd = events[i].data.fd) < 0)
                                {
                                        printf("just do it \n");
                                        continue;
                                }
                                #ifdef DEBUG
                                        printf("sock_fd ------%d\n",sock_fd);
                                #endif
                                n = recv(sock_fd, buf,5,0);
                                recv_number+=n;
                                sleep(2);
                                #ifdef DEBUG
                                        printf("recv n ----%d\n",n);
                                #endif
                                if(n< 0)
                                {
                                        printf("mark1");
                                        if (errno == ECONNRESET)
                                        {
                                                close(sock_fd);
                                                events[i].data.fd = -1;
                                        }
                                        else
                                                printf("sorry \n");
                                }
                                else if (n == 0)
                                {
                                        close(sock_fd);
                                        events[i].data.fd = -1;
                                }
                                buf[n] = '\0';
                                printf("read data %s\n",buf);
                                ev.data.fd=sock_fd;
                                ev.events=EPOLLOUT|EPOLLET;
                                epoll_ctl(epfd, EPOLL_CTL_MOD, sock_fd, &ev);
                                
                        }
                        else if(events[i].events&EPOLLOUT)
                        {
                                sock_fd = events[i].data.fd;
                                write(sock_fd, buf, n);
                                ev.data.fd=sock_fd;
                                ev.events=EPOLLIN|EPOLLET;
                                epoll_ctl(epfd,EPOLL_CTL_MOD,sock_fd,&ev);
                        }
                }
        }
        exit(0);
}
(END) 

可以客户端,见本博客,注意改下端口

http://blog.csdn.net/xluren/article/details/8043484



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值