#include<stdio.h>
#include<sys/epoll.h>
#include<signal.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<unistd.h>
#include<netinet/in.h>
#include<string.h>
#include<sys/types.h>
#include<fcntl.h>
#define MY_PORT 8848
#define MY_SIZE 100
int setnonblocking(int sockfd)
{
if(fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1)
{
return -1;
}
return 0;
}
int main(int argc,char *argv[])
{
int server_pid,client_pid,fd,ndfs;
int len,count;
fd_set insert,tmp_insert;
struct epoll_event ev;
struct epoll_event events[20];
// 生成服务器描述符,SOSCK_STREAM表示面向链接稳定传送,即为tcp协议;
// AF_INET表示ipv4,协议
server_pid = socket(AF_INET,SOCK_STREAM,0);
if(-1 == server_pid)
{
perror("socket error\n");
exit(-1);
}
// 定义网络结构体相关参数
struct sockaddr_in my_addr;
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MY_PORT);
my_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
len = sizeof(struct sockaddr);
printf("socket....\n");
// bind绑定
if(-1 == bind(server_pid,(struct sockaddr*)&my_addr,len))
{
perror("bind error\n");
exit(-2);
}
printf("binding...\n");
// listen监听,第二个参数为限制listen后还未来得及accept的链接数
if(-1 == listen(server_pid,5))
{
perror("listen error\n");
exit(-3);
}
printf("listening.....");
//fflush(stdout);
struct sockaddr_in your_addr = {0};
// 创建epoll
int epoll_fd = epoll_create(256);
ev.data.fd=server_pid;
ev.events=EPOLLIN|EPOLLET;
int size = sizeof(struct sockaddr_in);
// epoll事件注册
char buf[MY_SIZE];
epoll_ctl(epoll_fd,EPOLL_CTL_ADD,server_pid,&ev);//表示把server加入epoll的监听事件
for(;;)
{
bzero(buf,MY_SIZE);
ndfs = epoll_wait(epoll_fd,events,20,500);//20表示events变量有多大
for(fd = 0;fd<ndfs;++fd)
{
if(events[fd].data.fd == server_pid)
{
client_pid = accept(server_pid,(struct sockaddr*)&your_addr,&size);
if(-1 == client_pid)
{
perror("accept\n");
exit(-4);
}
setnonblocking(client_pid);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd=client_pid;
//把客户端加入epoll监听
epoll_ctl(epoll_fd,EPOLL_CTL_ADD,client_pid,&ev);
printf("accept sucess!\n");
}else if(events[fd].events&EPOLLIN) //EPOLLIN表示检测到输入,对应有EPOLLOUT为检测到输出
{
//收到数据填入buffer
if((count = recv(client_pid,buf,sizeof(buf),0)) <= 0)
{
close(fd);
printf("Client %d has left\n",fd);
}
else
{
//把buffer反馈给send
printf("%d\n",count);
printf("recv:%s\n",buf);
if(-1 == send(client_pid,buf,sizeof(buf),0))
{
perror("send");
exit(-3);
}
}
}
}
}
close(server_pid);
return 0;
}
一。下面简单说说epoll几个函数的作用,它们分别为epoll_create,epoll_ctl,epoll_wait
1.int epoll_create(int size)
这个函数即为创建epoll的文件描述符,它其实是在内核申请一空间,用来存放你想关注的socket fd上是否发生以及发生了什么事件。size就是你在这个epoll fd上能关注的最大socket fd数。
2.int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
这个函数用来把文件描述符加入修改删除epoll,第一个参数epfd表示epoll_create返回的文件描述符;
第二个参数op表示要注册的事件:EPOLL_CTL_ADD 注册、EPOLL_CTL_MOD 修 改、EPOLL_CTL_DEL 删除;
第三个参数fd表示添加的进入epoll监听的文件描述符;
第四个参数event表示指向epoll_event的指针;
此函数调用成功返回0,不成功返回-1;
3.int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)
该函数用于轮询I/O事件的发生;
参数:
epfd:由epoll_create 生成的epoll专用的文件描述符;
epoll_event:用于回传代处理事件的数组;
maxevents:每次能处理的事件数;
timeout:等待I/O事件发生的超时值(单位毫秒);
参数:
epfd:由epoll_create 生成的epoll专用的文件描述符;
epoll_event:用于回传代处理事件的数组;
maxevents:每次能处理的事件数;
timeout:等待I/O事件发生的超时值(单位毫秒);
-1相当于阻塞,0相当于非阻塞。一般用-1即可
返回发生事件数。
返回发生事件数。
二。事件结构体
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 */
};
常用的事件类型:
EPOLLIN :表示对应的文件描述符可以读;
EPOLLOUT:表示对应的文件描述符可以写;
EPOLLPRI:表示对应的文件描述符有紧急的数据可读
EPOLLERR:表示对应的文件描述符发生错误;
EPOLLHUP:表示对应的文件描述符被挂断;
EPOLLET:表示对应的文件描述符有事件发生;