epoll_data:
epoll_data中的fd是文件描述符
ptr提供了一个用户可用的指针
关于u32和u64是为了对齐,保证这个联合体长度为8个字节。
看了一下sys_epoll_x的实现,可以看到内核里epoll_event的定义
struct epoll_event {
因为ptr是一个指针,32位平台下指针长度u32,64BIT平台下指针长度是u64,这个是起到标识作用吧
所涉及到的函数有:
2、epoll_create函数
3、epoll_ctl函数
4、epoll_wait函数
epoll sever 示例
//
// a simple echo server using epoll in linux
//
//
//
// email:
//
#include <sys/signal.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/msg.h>
#include <netdb.h>
#include <unistd.h>
#include <stdarg.h>
#include <time.h>
#include <fcntl.h>
#define SERVICE "epollserver"
#define BUFSIZE 1024
#define TIMEOUT 30
#define PORT 7888
#define
#define MAX_EVENTS 1024
#define MAX_THREAD 300
struct myepoll_data {
};
static pthread_rwlock_t rwlock;
int iThreadCount;
int tootal=0;
int InitListenSocket(const char * service,short port);
void AcceptConn(int g_epollFd,int fd);
void RecvData(int g_epollFd,int g_sendFd,int fd);
void SendData(int g_sendFd,int fd, char* buf,int len);
void *writeThread(void *arg);
void *readThread(void *arg);
int main(int argc, char **argv)
{
printf("server running:port[%d]\n", PORT);
int child =0;
int num_childs=5;
while(!child)
{
if(num_childs>0)
{
switch(fork())
{
case -1:
printf("error in fork!");
return -1;
case 0:
printf("i am the child process, my process id is %d\n",getpid());
child=1;
break;
default:
num_childs--;
break;
}
}
}
// fork 5 个子进程
// create epoll
struct epoll_event ev = {0, {0}};
printf("create epoll failed.%d\n", g_epollFd);
int g_sendFd = epoll_create(MAX_EVENTS);
printf("create epoll failed.%d\n", g_sendFd);
ev.events = EPOLLIN | EPOLLET;
if (epoll_ctl(g_epollFd, EPOLL_CTL_ADD,listenFd, &ev) < 0) {
printf("epoll set insertion error: fd=%d\n", listenFd);
iThreadCount = 0;
pthread_t tid,r_tid;
pthread_attr_t attr;
if(pthread_attr_setstacksize(&attr, STACKSIZE) != 0)
return -1;
if(pthread_create(&r_tid,NULL,writeThread,(void *)g_sendFd)!=0)
{
printf("pthread_create writeThread error [%d]%s\n",errno,strerror(errno));
return -1;
}
//初始化读写锁
if((events[i].data.fd==listenFd)&&(events[i].events&EPOLLIN)) // accept event
{
printf("AcceptConn Event,process:{%d] \n",getpid());
AcceptConn(g_epollFd,events[i].data.fd);
}else
printf("epoll read event[%d]\n",getpid());
while(iThreadCount>MAX_THREAD)
{
printf("pthread_create error [%d]\n",iThreadCount);
usleep(500);
}
//RecvData(md->epollFd,md->fd);
md->epollFd2=g_sendFd;
if(pthread_create(&tid,&attr,readThread,(void *)md)!=0)
{
printf("pthread_create error [%d]%s\n",errno,strerror(errno));
}
}
// accept new connections from clients
void AcceptConn(int g_epollFd,int fd)
{
struct epoll_event evt = {0, {0}};
nfd = accept(fd, (struct sockaddr*)&sin, &len);
if(nfd==-1)
{
if(errno == EAGAIN)//没有连接需要接收了
{
//printf("%s: accept over,EAGAIN: %d\n", __func__, errno);
break;
}else
{
printf("%s: accept error,errno: %d\n", __func__, errno);
}
}
// set nonblocking
if(( fcntl(nfd, F_SETFL, O_NONBLOCK)) < 0)
{
printf("%s: fcntl nonblocking failed:%d\n", __func__, errno);
break;
}
struct myepoll_data* md =(struct myepoll_data*)malloc(sizeof(struct myepoll_data));
md->fd=nfd;
md->epollFd=g_epollFd;
evt.data.ptr=md;
if(epoll_ctl(g_epollFd,EPOLL_CTL_ADD,nfd, &evt)<0)
{
printf("accept EPOLL_CTL_ADD failed:%d\n", errno);
}
}
}
// receive data
void RecvData(int g_epollFd,int g_sendFd,int fd)
{
char buf[BUFSIZ];
struct epoll_event evt = {0, {0}};
int pos = 0;
while (1)
{
len = read(fd, buf+pos,sizeof(buf)-pos);
if(len > 0)
{
//printf("[recv],len:%d\n",len);
pos += len;
continue ;
}
else if ( len < 0 )
{
//printf("[recv] :ret[%d] errno [%d]\n",len,errno);
if ( errno == EAGAIN ){
//printf("[recv] complete,len:%d[%s]\n",pos,buf);
break;
}
else if ( errno == EINTR
else {
同一连接可能会出现两个客户端主动关闭的事件,一个errno是EAGAIN(11),一个errno是EBADF(9)
printf("[recv],some error occurs:%d %s\n",errno,strerror(errno));
break;}
// some error occurs
}
else // ( len == 0 )
{
printf("client disconnect\n");
epoll_ctl(g_epollFd,EPOLL_CTL_DEL,fd, &evt);
close(fd);
return ;
// client disconnect
}
}
epoll_ctl(g_epollFd,EPOLL_CTL_DEL,fd, &evt);
len=pos;
sleep(3);
struct myepoll_data* md =(struct myepoll_data*)malloc(sizeof(struct myepoll_data));
md->fd=fd;
md->data=buf;
md->epollFd=g_epollFd;
md->len=strlen(buf);
if(epoll_ctl(g_sendFd,EPOLL_CTL_ADD,fd, &evt)<0)
{
printf("SendData EPOLL_CTL_MOD failed:%d\n", errno);
}
}
void SendData(int g_epollFd,int fd, char* buf,int len)
{
retval += ret;
pos -= ret;
if(ret < 0)
{
if(errno == EINTR)
break;
//写缓冲队列已满,等待再写。
if(errno == EAGAIN)
usleep(500);
continue;
printf("[SendData errno [%d]%s\n",errno,strerror(errno));
break;
}
//printf("[SendData complete,len:%d][%s]\n",len,buf);
break;
tootal++;
printf("disconnect [%d][%d]\n",getpid(),tootal);
epoll_ctl(g_epollFd,EPOLL_CTL_DEL,fd, &evt);
close(fd);
}
void *readThread(void *arg)
{
pthread_rwlock_wrlock(&rwlock);//获取读取锁
iThreadCount++;
printf("workThread start %d\n",iThreadCount);
pthread_rwlock_unlock(&rwlock);
struct myepoll_data* md =(struct myepoll_data*)arg;
pthread_rwlock_wrlock(&rwlock);//获取读取锁
iThreadCount--;
pthread_rwlock_unlock(&rwlock);
pthread_exit(NULL);
}
void *writeThread(void *arg)
{
printf("[epoll_wait2]errno=%d,%s\r\n",errno,strerror(errno));
pthread_exit(NULL);
}
int InitListenSocket(const char * service,short port)
{
struct servent *pse;
struct protoent *ppe;
struct sockaddr_in sin;
bzero(&sin, sizeof(sin));
if (pse = getservbyname(service, "tcp"))
sin.sin_port = htons(port);//ntohs((u_short)pse->s_port));
else if((sin.sin_port = htons(port)) == 0)
exit(1);//errexit("can't get service\n");
if ((ppe = getprotobyname("tcp")) == 0)exit(1);
//errexit("can't get protocol entry\n");
if(listenFd==-1)
{
perror("socket");
}
fcntl(listenFd, F_SETFL, O_NONBLOCK); // set non-blocking
{
perror("bind");
}
{
perror("listen");
}
printf("server listen fd=%d\n", listenFd);
return listenFd;
}